Writing a TCP/UDP server type for Caddy

except there not dns server plugins, but they don’t need to, because no middleware.

Yep. Any server type can be shutdown or started, which is why it doesn’t need to be tied to a specific server type.

TLS knows the »SNI extension«. That is, the server name will be sent before the handshake completes, in cleartext. (That’s why you shouldn’t run stuff like SecureDrop or the like on its own domain.) It’s stored here:

ClientHelloInfo.ServerName

2 Likes

Hey @pieterlouw - I talked to someone at my university today named Jordan who wants to get on board and help with your TCP/UDP server plugin. Might be a few weeks out still, but he’ll contact you soon I think!

That’s great news!

3 posts were split to a new topic: TLS storage plugin type for sharing certs

So I’ve done quite a bit to add tls to the plugin.

I have registered the callback and the config getter caddy.RegisterParsingCallback(serverType, "tls", activateTLS)

caddytls.RegisterConfigGetter(serverType, func(c *caddy.Controller) *caddytls.Config {return GetConfig(c).TLS})

The activateTLS follow all the steps stated in the wiki guide.

I also added a tlshost directive to set the hostname the tls will use i.e

echo :22017 {
    tlshost echo.caddynet.com
}

Before I call tls.Listen I do the necessary call to caddytls.MakeTLSConfig to get the tlsConfig to use in tls.Listen

When I start caddy I get the Let’s Encrypt questionaire. (I cancelled as I’m not on an owned domain)

I tried to test with the self-signed option like this

echo :22017 {
    tlshost localhost
    tls self_signed
}

But then I recive an error: tls: neither Certificates nor GetCertificate set in Config when I call tls.Listen from my server.
I have double checked and debugged quit for a while now and can’t exactly figure out what I’m doing wrong here. Have I missed something?

caddy-net (main repo)
caddy-net (tls branch) [EDIT: tls brand merged and deleted]

I’d suggest going into config.go and see what configMap looks like by printing it: https://github.com/mholt/caddy/blob/4e1229e7c9bd5643ed079f3dafa25df4e426da56/caddytls/config.go#L350

And make sure this line gets executed: https://github.com/mholt/caddy/blob/4e1229e7c9bd5643ed079f3dafa25df4e426da56/caddytls/config.go#L267

Make sure everything checks out there. Hope that helps!

Edit: How do you feel about just using the directive name host instead of tlshost? In theory the hostname wouldn’t have to be limited to TLS.

Thanks,

After adding some traces I could see configMap loaded and the line mentioned did execute.
It turns out that I used the wrong function when creating a listener for tls.
I used tls.Listen() but when I switched to tls.NewListener() it works. (Still unsure why exactly…)

I don’t have a problem naming the directive host - I named it tlshost as I thought that was the only reason a host would need to be specified. Do you see a reason why it maybe could be plural (hosts)?

I’ll finish off the tls for the proxy and merge then I guess it’s just tests that left.[EDIT: I have implemented tls for the proxy as well and merged to master]

I might need help with testing auto-TLS as at the momenet I don’t own a domain of my own.

Pieter

Awesome! I have a domain you can borrow, just let me know which IP to point it at. You’ll have to make sure ports 80 and 443 are forwarded within your home to your computer. You can DM me the IP address.

Edit: Either host or hosts is fine! They are both better than tlshost(s).

tls.NewListener() returns an unstarted listener, but tls.Listen() is a started listener. You want an unstarted one.

1 Like

Also might just point out that this mob do free short term domain registrations, great for testing stuff.

I can give you a subdomain under miek.nl, coredns.io or dnssex.nl (last one if a personal favorite :slight_smile: )

Let me know your IP and what name you want at miek@miek.nl (you should have a static home IP of course)

4 Likes

Ha, very nice.

1 Like

I have created a domain for myself now.I created an A DNS record echo.leastsignificantbit.co.za and pointed it to a Google VM server external IP Address. After that I setup caddy with the net plugin on the server with the following Caddyfile:

echo :12017 {
    host echo.leastsignificantbit.co.za
}

I start caddy with the net plugin and Let’s Encrypt prompts for my email. After that I receive an error: 2017/03/31 22:44:01 [echo.leastsignificantbit.co.za] failed to get certificate: [echo.leastsignificantbit.co.za] error presenting token: Could not start HTTPS server for challenge -> listen tcp :443: bind: permission denied [EDIT: after tracking this message in the source code it looks like it’s a message from the ACME client]

I do have port 443 open on the server firewall, but nothing is listening on that port.

I tried the same on my dev machine behind my personal internet after pointing the dns record to my personal internet IP address but I get the same error.

You need to make sure you give Caddy permission to bind to low ports; setcap can do this (see FAQ) or you can just run as root.

Thanks @matt,
I run as root (sudo) now but get a different error now:
failed to get certificate: acme: Error 400 - urn:acme:error:connection - Could not connect to echo.leastsignificantbit.co.za

I pointed the domain above to my local internet and forwarded port traffic to my laptop.

Also, when if I dig +short echo.leastsignificantbit.co.za I get the correct IP address.

I tried to a different server (running on Google cloud) and pointed play.leastsignificantbit.co.za to the external IP on that server. When I run caddy on there I get a different (but similar) error:
failed to get certificate: acme: Error 400 - urn:acme:error:connection - DNS problem: NXDOMAIN looking up A for play.significantbit.co.za

Again, if I dig +short play.leastsignificantbit.co.za I get the correct IP address.

If I switch off tls in the Caddyfile I can telnet into both domain names and on the listening port.

Any ideas what I might be doing wrong? Could it be something to do with my hosting company and their DNS?

For ACME-related errors, there’s more output than that, there should be more lines saying what the result of their DNS lookup was, etc. But yeah, so far it looks like they had trouble connecting to your machine.

Want me to try it? DM me when you want me to try connecting from my machine. If I can’t, then it’s definitely an issue with your network configuration.

failed to get certificate: acme: Error 400 - urn:acme:error:connection - Could not connect to echo.leastsignificantbit.co.za

This means that the ACME server found a server on the other end of echo.leastsignificantbit.co.za, but couldn’t open a HTTP(S) connection to it.

This one is different - it tells me that your own DNS server is updating quicker than the one that LetsEncrypt is using for their ACME servers. I expect the solution will be to wait for a little while for DNS propagation to complete.

I don’t know if LE uses Google’s public DNS or not, but anecdotally, I’ve found that if dig @8.8.8.8 +short example.com resolves, LetsEncrypt can run it.

I believe LE does an authoritative lookup each time. Some providers take hours to apply changes though, regardless of propagation.

Good point, but if he can dig it and get the right response, at very least the name servers and his DNS server must be updated, right?