Edit 3: Tested with wg-quick on Arch, same issue re-occurs. So, let's say we have a peer on 192.168.1.1/24 with internal (wireguard) IP of 10.0.0.1/24, but we also want to route through it to rest of 192.168.1.0/24.
Instead of nice AllowedIPs = 10.0.0.0/24,192.168.1.0/24, it would have to be:
AllowedIPs = 10.0.0.0/24, 192.168.1.1/32, 192.168.1.2/31, 192.168.1.4/30, 192.168.1.8/29, 192.168.1.16/28, 192.168.1.32/27, 192.168.1.64/26, 192.168.1.128/25
Or there's something else going wrong. I only tried on Arch. Welp, as I said, it's not a thing that occurs with WG Tunnel on Android.
Edit 2: Hypothesis confirmed. Excluding the endpoint from AllowedIPs in NetworkManager solves the issue. However, this isn't a problem with 0.0.0.0/0, nor with WG Tunnel app on Android. I'll have to check with wg-quick. That seems most official.
Summary: NetworkManager tries to route traffic to WG peer over the same WG interface, and its /32 has to be excluded.
Edit: I noticed one thing, I'll try excluding the peer endpoint from AllowedIPs. It seems weird if it tries to connect to it over the interface between the 2 peers, which is of course impossible, but maybe? However, it is not matched by 0.0.0.0/0. Welp, time to experiment.
So, for 2 years I thought that NetworkManager Wireguard implementation is simply broken.
When I used a list of address ranges, like I should be (and am) able to do with Wireguard, I couldn't get any traffic through, however 0.0.0.0/0,::/0 would work.
Today I discovered something... interesting. It actually works... with a smaller list of AllowedIPs. Although even a larger list still ends up being shown by ip r.
So I went to AllowedIPs calculator as usual, created a desired list, pasted it in, and started removing IP ranges until I could ping a remote peer.
Problem solved? Well, no. I hoped it would be the limitation in number of routes, but it (also) seems to depend on route size.
Examples:
This is too much:
0.0.0.0/5,8.0.0.0/7,11.0.0.0/8,12.0.0.0/6,16.0.0.0/4,32.0.0.0/3,64.0.0.0/2,128.0.0.0/3,160.0.0.0/5,168.0.0.0/6,172.0.0.0/12,172.32.0.0/11,172.64.0.0/10,172.128.0.0/9,10.147.0.0/24
Removing one of the routes, 172.128.0.0/9 makes it work.
0.0.0.0/5,8.0.0.0/7,11.0.0.0/8,12.0.0.0/6,16.0.0.0/4,32.0.0.0/3,64.0.0.0/2,128.0.0.0/3,160.0.0.0/5,168.0.0.0/6,172.0.0.0/12,172.32.0.0/11,172.64.0.0/10,10.147.0.0/24
Time for mystery start. Keeping the same number of routes, but decreasing the size of one of them (second last) also makes it work:
0.0.0.0/5,8.0.0.0/7,11.0.0.0/8,12.0.0.0/6,16.0.0.0/4,32.0.0.0/3,64.0.0.0/2,128.0.0.0/3,160.0.0.0/5,168.0.0.0/6,172.0.0.0/12,172.32.0.0/11,172.64.0.0/10,172.128.0.0/10,10.147.0.0/24
Naturally, I tried breaking up 172.128.0.0/9 into 172.128.0.0/10 and 172.192.0.0/10, which breaks it again.
So, it seems to depend on both number and size of the routes. After all, larger ones alone worked.
Yakuake terminal: https://apps.kde.org/yakuake/