[systemd-devel] Enable port forwarding via upnp

Lennart Poettering lennart at poettering.net
Wed Feb 25 12:40:10 PST 2015


On Wed, 25.02.15 21:14, Kai Krakow (hurikhan77 at gmail.com) wrote:

> > 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. 

Yes, that's what I understood.

> 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.

Well, to get this natively integrated in networkd I'd prefer avoiding
an extra dep. I wonder if we can avoid pulling this in if we stick to
the minimal upnp bits necessary to set up the port forwarding. I mean,
this is after all just a client, not a server...

> 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.

Yeah, I agree. Though I'd explicitly clarify that this is about
Upnp. Hence call it ExposeUPNP= or so.

> 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

I'd avoid this. If people don't use socket activation, then they
might as well configure this in networkd itself...

> 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.

Hmm, the API doesn't look that great to me that I'd be enthusiastic to
depend on this I must say...

> > 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.

Sure, you could hack that up with the daemon that miniupnp provides.

> 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.

PID 1 exports this already, via dbus. It's all readily accessible.

> 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?

bus signals are sent out when units change their state.

> 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?

they are exposed as properties on the bus.

Lennart

-- 
Lennart Poettering, Red Hat


More information about the systemd-devel mailing list