|
|
|
@ -13,9 +13,11 @@ import (
|
|
|
|
|
"io"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"log"
|
|
|
|
|
"net"
|
|
|
|
|
"net/http"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/tailscale/wireguard-go/wgcfg"
|
|
|
|
|
"golang.org/x/crypto/acme/autocert"
|
|
|
|
@ -23,6 +25,7 @@ import (
|
|
|
|
|
"tailscale.com/derp"
|
|
|
|
|
"tailscale.com/derp/derphttp"
|
|
|
|
|
"tailscale.com/logpolicy"
|
|
|
|
|
"tailscale.com/stun"
|
|
|
|
|
"tailscale.com/tsweb"
|
|
|
|
|
"tailscale.com/types/key"
|
|
|
|
|
)
|
|
|
|
@ -35,6 +38,7 @@ var (
|
|
|
|
|
hostname = flag.String("hostname", "derp.tailscale.com", "LetsEncrypt host name, if addr's port is :443")
|
|
|
|
|
mbps = flag.Int("mbps", 5, "Mbps (mebibit/s) per-client rate limit; 0 means unlimited")
|
|
|
|
|
logCollection = flag.String("logcollection", "", "If non-empty, logtail collection to log to")
|
|
|
|
|
runSTUN = flag.Bool("stun", false, "also run a STUN server")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type config struct {
|
|
|
|
@ -135,6 +139,10 @@ func main() {
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
if *runSTUN {
|
|
|
|
|
go serveSTUN()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
httpsrv := &http.Server{
|
|
|
|
|
Addr: *addr,
|
|
|
|
|
Handler: mux,
|
|
|
|
@ -190,3 +198,58 @@ func debugHandler(s *derp.Server) http.Handler {
|
|
|
|
|
`)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func serveSTUN() {
|
|
|
|
|
pc, err := net.ListenPacket("udp", ":3478")
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("failed to open STUN listener: %v", err)
|
|
|
|
|
}
|
|
|
|
|
log.Printf("running STUN server on %v", pc.LocalAddr())
|
|
|
|
|
var (
|
|
|
|
|
stunReadErrors = expvar.NewInt("stun-read-error")
|
|
|
|
|
stunWriteErrors = expvar.NewInt("stun-write-error")
|
|
|
|
|
stunReadNotSTUN = expvar.NewInt("stun-read-not-stun")
|
|
|
|
|
stunReadNotSTUNValid = expvar.NewInt("stun-read-not-stun-valid")
|
|
|
|
|
stunReadIPv4 = expvar.NewInt("stun-read-ipv4")
|
|
|
|
|
stunReadIPv6 = expvar.NewInt("stun-read-ipv6")
|
|
|
|
|
stunWrite = expvar.NewInt("stun-write")
|
|
|
|
|
)
|
|
|
|
|
var buf [64 << 10]byte
|
|
|
|
|
for {
|
|
|
|
|
n, addr, err := pc.ReadFrom(buf[:])
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("STUN ReadFrom: %v", err)
|
|
|
|
|
time.Sleep(time.Second)
|
|
|
|
|
stunReadErrors.Add(1)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
ua, ok := addr.(*net.UDPAddr)
|
|
|
|
|
if !ok {
|
|
|
|
|
log.Printf("STUN unexpected address %T %v", addr, addr)
|
|
|
|
|
stunReadErrors.Add(1)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
pkt := buf[:n]
|
|
|
|
|
if !stun.Is(pkt) {
|
|
|
|
|
stunReadNotSTUN.Add(1)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
txid, err := stun.ParseBindingRequest(pkt)
|
|
|
|
|
if err != nil {
|
|
|
|
|
stunReadNotSTUNValid.Add(1)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if ua.IP.To4() != nil {
|
|
|
|
|
stunReadIPv4.Add(1)
|
|
|
|
|
} else {
|
|
|
|
|
stunReadIPv6.Add(1)
|
|
|
|
|
}
|
|
|
|
|
res := stun.Response(txid, ua.IP, uint16(ua.Port))
|
|
|
|
|
_, err = pc.WriteTo(res, addr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
stunWriteErrors.Add(1)
|
|
|
|
|
} else {
|
|
|
|
|
stunWrite.Add(1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|