Lennart Poettering <[email protected]> schrieb: > On Wed, 25.02.15 08:16, Kai Krakow ([email protected]) wrote: > >> Hello! >> >> Is it possible to somehow create a service which enables port forwardings >> on my router using upnp? Currently, I guess it is not possible (except >> maybe using ExecPost or ExecPre and the upnpc program). But when my >> client IP changes via DHCP, it should be reapplied. Also, it needs to be >> maintained as the programmed port forwardings would timeout and be >> cleared from the router after a while. So it needs to be hooked up to >> systemd-networkd somehow (at least that is what I am using). > > Not really. Such a upnp port setup tool could just subscribe to rtnl > and update the router's configuration dynamically each time the local > configuration is changed, without having to know anything about > networkd, NM or anything else.
Okay, didn't know about rtnl. I will look into it. It makes sense to keep things separated to allow people to choose between networks, NM or anything else. > That said I think it wouldn't be too far off I figure to add logic for > this to networkd. I mean, it speaks a variety of client side protocols > already, and this could just be one more. The major difference though > is that upnp is a frickin insane pseudo-HTTP XML craziness, while > DHCP, IPv4LL and so on are much more low-level. That said, I figure > we'll have some kind of HTTP logic in networkd eventually anyway to > support wispr and things like that, so maybe doing upnp wouldn't be > completely off either... To make sure we speak the same language: I propose to have a upnp client only, not a server - my system is a desktop, not a router. I just want to offer some services on my public router IP to get access from outside without having to resort to static IP assignment and without having to edit port numbers in two or more places. As far as I know, there's already a upnp client library one could link to and use that to talk to the upnp server on the router. My idea is to add a config option to socket activated services which just reuses the Listen directives to publish the ports to upnp on the router. Maybe something like [Socket] ListenStream=22 PublishStream=yes which would instruct yet the to be planned upnp client to create a port forwarding for 22/tcp on the router. The same could work for ListenDatagram. Of course this only makes sense, if sockets are not bound to localhost only. It may make sense to move "PublishStream" to the service section of a unit (as "PublishStreams=yes") so it could publish all sockets from each socket unit associated with it - though I'm not sure if this is wanted as it moves socket logic into another section. And it probably doesn't make sense either because the service is started lazily when triggered by the sockets - which suggests the upnp mapping should have run earlier (when the socket unit was started). But it would make sense for non-socket-activated services where the PublishStreams directive could just be reused in the following form: [Service] PublishStreams=22 # SSH server or [Service] PublishStreams=80,443 # WWW server [Service] PublishDatagrams=51900-51999 # example service publishing 51900-99/udp [Service] PublishDatagrams=51900-51999:5190 # publish 51900-99/udp as 5190-99/udp on eth* [Service] PublishStreams=8080:80 # publish 8080/tcp on the router as 80 on eth* So instead of defining port mappings on the router manually, this would be done automatically, depending on which services/sockets are started. > I figure if we can do this with existing deps, the internal XML parser > and so on, this could work. I.e. a minimal upnp port forwarding > library รก la sd-dhcp would be acceptable... It should not take much more than a wrapper around libminiupnpc.so, it's designed around having the smallest possible footprint: http://miniupnp.free.fr/ It comes with a small test client program "upnpc" which provides all the stuff needed to implement the above ideas. >> So I guess this logic should be built into systemd-networkd, maybe >> offering some dbus interface also. And service and/or socket files could >> have a flag to enable upnp forwards. This way, systemd-networkd knows >> about the registered forwards and maintains them, and systemd will >> trigger registration/unregistration on it whenever services start or stop >> which have such flags enabled. By using dbus, this could be an interface >> implemented by other network management daemons, too. > > This is already the second step... It kinda opens another can of worms > though: we discussed on and off how integration between mDNS/DNS-SD > and .socket units could look like. This port forwarding thing and the > mDNS hookup are somewhat related: in both cases we have a concept of > actively registering with some external code as long as as a socket is > up. > > Originally, when we discussed that in the mDNS context I thought of > simply using ExecStartPre= and ExecStopPre= for this, and forking off > a tool that pushes the mDNS registration into avahi/resolved as long > as the socket is up. But I ended not liking this idea, since in most > cases this would mean having one addition process around, that does > some bits when it starts up, then only hangs around, and then does a > bit more when it shuts down. Hanging around pointlessly is bad > though. So the next idea was maybe then PID 1 could simply call > directly into avahi/resolved via async bus calls, so that we have no > extra pointless processes hanging around. > > However, that idea I don't like either, because it makes PID 1 client > of another daemon, and I really don't like that, I'd really prefer it > the other way round: the higher level daemons should call into the > lower level daemons, and subscribe to them, but the lower level > daemons should never call into the higher level daemons... > > In networkd we followed this correct stacking design quite > nicely. networkd never pushes NTP servers into timesyncd or DNS > servers into resolved. Instead, timesyncd and resolved subscribe to > what networkd announces and pull the data out that. Most likely that's > the logic we should follow here too: > > - For the port forwarding logic we should introduce a new .socket > property, that PID 1 doesn't really do much with, except exporting > it on the bus > > - networkd susbcribes to .socket units starting and stopping in > PID 1, and pulls out that one property of them, and acting on it. > > Similar, we would handle the mDNS case: the .socket units would gain a > new DNSSDService property, that resolved then keeps track of an > operates on. > > I hope that makes some sense? Well, then I suppose it would be better to have a standalone daemon, let's call it systemd-upnpclientd. This service would subscribe to rtnl you mentioned above. This will make it independent of systemd-networkd and could support other implementations like NM etc. Next step, I'm not sure however: It also needs to gain knowledge about every socket monitored by systemd and every socket mentioned in service files, as outlined in my examples. But I'm sure PID1 could simply export such information. Or alternatively: You mentioned that one could subscribe to units starting and stopping, so we could simply pull out the information needed. I currently see problems with both approaches: When getting exported info from systemd about sockets to be published on the router: How do we get notified about changes introduced by starting or stopping units? When subscribing to starting and stopping of units, how do we pull the info from the unit files if systemd-upnpclientd gets started after some units wanting to publish sockets are already up? Putting all together, and after reading through your thoughts, I'd favor a solution of a standalone daemon instead of putting possibly unrelated stuff into PID1 or networkd - with the exception of maybe exporting additional information. -- Replies to list only preferred. _______________________________________________ systemd-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/systemd-devel
