Open cecton opened 7 months ago
Hi there!
Thanks for sharing your improvement with others through this PR.
I'm unlikely to find the time to review it properly before the weekend. Apologies for that.
The idea to shutdown the service after idling for some time is excellent. :-) In go, for HTTP servers, that would be the IdleTracker if you ever need sth. like it.
You get "timeouts" as seen by the remotes (PalWorld clients) on missing return packets indeed. And your suspicion is (likely) correct, without an address translation they either get suppressed by your server machine's datacenter, or dismissed by the remotes. iptables
could work (iptables snat), but I found tc filter
to be the most efficient solution. There's an example in the README. Goes into PreExec=
in your systemd unit file. From top of my head:
tc qdisc add dev ext0 ... handle 10: htb
tc filter add dev ext0 parent 10: ... match ip src 10.0.0.0/16 \
action nat egress 10.0.0.0/16 6.5.4.3
Thanks! I still haven't found a working solution... this whole thing is really out of my league but using tc is yet another step for me. I ended up with this:
sudo modprobe sch_htb
sudo tc qdisc add dev eth0 root handle 1: htb
sudo tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip protocol 17 0xff match u16 0x2093 0xffff at 22 action nat egress 127.0.0.1 10.0.30.125
I made my own non-transparent UDP proxy if you're curious: https://github.com/cecton/systemd-cecile-proxy
Nice! Release it as binary perhaps, for I fear not everyone will know how to or be inclined to compile it from scratch in a language currently rarely used.
Oh no it's in development, there isnt even a readme
When you feel comfortable, drop me a line and I’ll list it in the README under “alternatives.” :-)
Going through your code I’ll merge it after promoting the argument to a parameter, called --exit-after-idle
or similar. (Maybe there’s a more elegant way of parsing than → https://github.com/systemd/systemd/blob/027d9f90966fba38500530b1fb19defa38d12a03/src/resolve/resolvectl.c#L3684C12-L3684C29 )
Ignore the merge conflict Github could show. I’m working on the console.
You should probably call it --exit-idle-time
to stay consistent with systemd's socket-proxy: https://github.com/systemd/systemd/blob/887b2529eb4361838be3260e9b3b0f6c04246699/src/socket-proxy/socket-proxyd.c#L593
I want to add TCP proxy using the splice()
method like they do on systemd's socket-proxyd. So I can have a single system unit file with a few sockets of different type for games that have multiple ports. (Apparently lot of games have these RCON port for communicating with the server.)
Hello,
I'm currently playing Palworld but the dedicated server does not currently have an option to pause when no one is connected. This consume precious energy for nothing when no one is connected.
I don't know much about C and systemd but I managed to update systemd-transparent-udp-forwarderd to accept an "activity timeout" parameter at the end of its arguments. When provided, if there is nothing on the network during that amount of time (in seconds), then the service stops. I also added a line in the proxy service to allow the stop to be propagated to the actual server.
To test I made a simple UDP server and it worked fine. Unfortunately I couldn't make systemd-transparent-udp-forwarderd work with Palworld, even without my changes. I can see in the status message that some messages are being transferred but the client fails to join with the generic "timeout" error. When I look at the code I see nothing to handle the messages coming back from the game server, could this be related? Maybe I need to add a iptables rule or something?
Anyway... maybe I messed up something or Palworld don't work well with systemd-transparent-udp-forwarderd. But the feature I made does work and might be worth to keep. I'll let you be the judge of that.
Here are my unit files in case you can see something is wrong:
(The dedicated server and proxy are on the same remote machine, only the game client itself is on my machine.)
palworld.service
:palworld-proxy.service
:palworld-proxy.socket
:Test UDP server:
(copy-pasted from the doc mostly https://doc.rust-lang.org/std/net/struct.UdpSocket.html#method.connect )
(The server port is different and the service are somewhat similar.)
Test commands:
sudo sh -c 'echo "xx" > /dev/udp/127.0.0.1/27000'
sudo sh -c 'echo "exit" > /dev/udp/127.0.0.1/27000'