microsoft / cpprestsdk

The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services.
Other
7.91k stars 1.64k forks source link

http_listener using '+' does not work on ubuntu 22.04 #1709

Open jjoachim opened 2 years ago

jjoachim commented 2 years ago

I'm noticing a weird issue on Ubuntu 22.04 where the wildcard '+' doesn't seem to work as intended when instantiating a server. It serves localhost, but no other addresses that route back to the port (127.0.01, or the actual local ip address). I can explicitly list each one I want listened to and it works, but the wildcard doesn't. I'm not sure about what all internally is happening, but it could either be a problem trying to match multiple addresses or the wildcard simply not working.

To be clear, everything works as intended with Ubuntu 18.04. We updated our systems to the new 22.04 LTS and this problem came up consistently across several network configurations. Did something in 22.04 break the wildcard?

      uri_builder uri;
      uri.set_scheme(U("http"));
      uri.set_port(port);

      //uri.set_host(U("+")); //localhost only
      //uri.set_host(U("127.0.0.1")); //works
      uri.set_host(SystemUtils::GetInternalIp()); //works

      mServer = http_listener(uri.to_uri());

      //original way to construct a listener before debugging problems
      //string address = "http://+:" + port; //localhost only, used to work for localhost, 127.0.0.1, and internal ip
      //mServer = http_listener(address);

EDIT: I can run multiple servers simultaneously, one for localhost (which also covers 127.0.0.1) and one for the ip address assigned by the router. I think it's just an issue with the wildcard?

barcharcraz commented 2 years ago

I suspect this is something to do with how asio handles calls to query(port, opts) (ones that don't include the address at all) as that's what we do for "+", (and we only support "+" alone, not with other stuff). As far as I can tell this is a pretty nonstandard extension anyway.

Another possibility is that the way networking is configured changed between 18.04 and 22.04, to see if this is true I would first compare routing and ip assignments (and maybe links, and policies) between the systems, and then trace the networking syscalls on each system. I have seen the transition from the absolutely accursed old ifupdown scripts to systemd-networkd or NetworkManager break many configurations, and if you were doing something as radical as assigning an address like 192.168.0.4 to lo then I would not be surprised if the compat shims didn't handle it. You can see the routing table with ip route list table all, They are basically the same on my machine between ubuntu 18.04 and debian bullseye, but the net config for each is different (one is wsl, one is a "normal" hyperv vm). You could also check the nftables and iptables configurations, I could see having a rule that blocks sending packets with a loopback dest and a non-loopback source.

Do you get resolver response from glibc (getent hosts) for localhost that you expect?

In any case what address does the socket actually get bound to by the system, and what does routing look like to that address? I would not expect packets with src address of 192.168.whatever to end up getting routed to something bound to localhost, unless your routing rules are quite, quite strange.

jjoachim commented 2 years ago

To be honest, most of this is above me and I'm not quite sure what you're asking. I just know that on 22.04, the '+' wildcard in the uri to instantiate the server doesn't work, but instantiating separate servers to handle localhost routes and whatever ip the router gave us (found through parsing ifconfig) seemed to work.

getend hosts I think gives this, but not sure what I should be expecting:

$ getent hosts
127.0.0.1       localhost
127.0.1.1       <censored user name>
127.0.0.1       ip6-localhost ip6-loopback

To be clear, our machines run on local networks using intra-router ip's directly. So if the machine's ip is 10.1.1.74, then we use http://10.1.1.74:<port>/api to access the api's, which is just instantiated with http_listener("10.1.1.74") with support() using REST methods. We don't use DNS routing or anything to get to our devices.