Make the CLI configurable #1
15
Dockerfile
15
Dockerfile
@ -4,25 +4,20 @@ WORKDIR /app
|
|||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
RUN go build -o /app/local-ip
|
RUN go build
|
||||||
|
|
||||||
FROM gcr.io/distroless/base-debian12:latest
|
FROM gcr.io/distroless/base-debian12:latest
|
||||||
|
|
||||||
WORKDIR /local-ip
|
WORKDIR /local-ip
|
||||||
|
|
||||||
COPY --from=build /app/local-ip /local-ip/local-ip
|
COPY --from=build /app/local-ip.sh /local-ip/local-ip.sh
|
||||||
COPY --from=build /app/http/static /local-ip/http/static
|
COPY --from=build /app/http/static /local-ip/http/static
|
||||||
|
|
||||||
VOLUME /local-ip/.lego
|
VOLUME /local-ip/.lego
|
||||||
|
|
||||||
# DNS
|
# DNS HTTP HTTPS
|
||||||
EXPOSE 53/udp
|
EXPOSE 53/udp 80/tcp 443/tcp
|
||||||
# HTTP
|
|
||||||
EXPOSE 80/tcp
|
|
||||||
# HTTPS
|
|
||||||
EXPOSE 443/tcp
|
|
||||||
|
|
||||||
USER root
|
USER root
|
||||||
|
|
||||||
# TODO: make these configurable too
|
CMD ["/local-ip/local-ip.sh"]
|
||||||
CMD ["/local-ip/local-ip", "--domain", "local-ip.sh", "--email", "admin@local-ip.sh", "--nameservers", "ns1.local-ip.sh.,ns2.local-ip.sh."]
|
|
||||||
|
73
cmd/root.go
73
cmd/root.go
@ -2,29 +2,48 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/mail"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/asaskevich/govalidator"
|
||||||
"github.com/go-acme/lego/v4/lego"
|
"github.com/go-acme/lego/v4/lego"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
"local-ip.sh/certs"
|
||||||
|
"local-ip.sh/http"
|
||||||
"local-ip.sh/utils"
|
"local-ip.sh/utils"
|
||||||
|
"local-ip.sh/xip"
|
||||||
)
|
)
|
||||||
|
|
||||||
var command = &cobra.Command{
|
var command = &cobra.Command{
|
||||||
Use: "local-ip.sh",
|
Use: "local-ip.sh",
|
||||||
PreRun: func(cmd *cobra.Command, args []string) {
|
PreRun: func(cmd *cobra.Command, args []string) {
|
||||||
nameservers, err := cmd.Flags().GetString("nameservers")
|
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
|
||||||
if err != nil {
|
viper.SetEnvPrefix("XIP")
|
||||||
utils.Logger.Fatal().Err(err).Msg("Unexpected error")
|
viper.AutomaticEnv()
|
||||||
}
|
|
||||||
viper.Set("NameServers", strings.Split(nameservers, ","))
|
|
||||||
|
|
||||||
staging, err := cmd.Flags().GetBool("staging")
|
email := viper.GetString("Email")
|
||||||
|
_, err := mail.ParseAddress(email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Logger.Fatal().Err(err).Msg("Unexpected error")
|
utils.Logger.Fatal().Err(err).Msg("Invalid email address")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
domain := viper.GetString("Domain")
|
||||||
|
if !govalidator.IsDNSName(domain) {
|
||||||
|
utils.Logger.Fatal().Err(err).Msg("Invalid domain")
|
||||||
|
}
|
||||||
|
|
||||||
|
nameservers := strings.Split(viper.GetString("nameservers"), ",")
|
||||||
|
for _, ns := range nameservers {
|
||||||
|
if !govalidator.IsIPv4(ns) {
|
||||||
|
utils.Logger.Fatal().Err(err).Str("ns", ns).Msg("Invalid name server")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
viper.Set("NameServers", nameservers)
|
||||||
|
|
||||||
|
staging := viper.GetBool("staging")
|
||||||
var caDir string
|
var caDir string
|
||||||
if staging {
|
if staging {
|
||||||
caDir = lego.LEDirectoryStaging
|
caDir = lego.LEDirectoryStaging
|
||||||
@ -35,36 +54,32 @@ var command = &cobra.Command{
|
|||||||
|
|
||||||
parsedCaDirUrl, _ := url.Parse(caDir)
|
parsedCaDirUrl, _ := url.Parse(caDir)
|
||||||
caDirHostname := parsedCaDirUrl.Hostname()
|
caDirHostname := parsedCaDirUrl.Hostname()
|
||||||
email := viper.GetString("Email")
|
|
||||||
|
|
||||||
viper.Set("AccountFilePath", fmt.Sprintf("./.lego/accounts/%s/%s/account.json", caDirHostname, email))
|
viper.Set("AccountFilePath", fmt.Sprintf("./.lego/accounts/%s/%s/account.json", caDirHostname, email))
|
||||||
viper.Set("KeyFilePath", fmt.Sprintf("./.lego/accounts/%s/%s/keys/%s.key", caDirHostname, email, email))
|
viper.Set("KeyFilePath", fmt.Sprintf("./.lego/accounts/%s/%s/keys/%s.key", caDirHostname, email, email))
|
||||||
|
|
||||||
utils.InitConfig()
|
utils.InitConfig()
|
||||||
},
|
},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
c := utils.GetConfig()
|
n := xip.NewXip()
|
||||||
fmt.Printf("%#v\n", c)
|
|
||||||
fmt.Println(c)
|
|
||||||
// n := xip.NewXip()
|
|
||||||
|
|
||||||
// go func() {
|
go func() {
|
||||||
// account := certs.LoadAccount()
|
// try to obtain certificates once the DNS server is accepting requests
|
||||||
// certsClient := certs.NewCertsClient(n, account)
|
account := certs.LoadAccount()
|
||||||
|
certsClient := certs.NewCertsClient(n, account)
|
||||||
|
|
||||||
// time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
// certsClient.RequestCertificates()
|
certsClient.RequestCertificates()
|
||||||
|
|
||||||
// for {
|
for {
|
||||||
// // try to renew certificate every day
|
// afterwards, try to renew certificates once a day
|
||||||
// time.Sleep(24 * time.Hour)
|
time.Sleep(24 * time.Hour)
|
||||||
// certsClient.RequestCertificates()
|
certsClient.RequestCertificates()
|
||||||
// }
|
}
|
||||||
// }()
|
}()
|
||||||
|
|
||||||
// go http.ServeHttp()
|
go http.ServeHttp()
|
||||||
|
|
||||||
// n.StartServer()
|
n.StartServer()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,15 +97,13 @@ func Execute() {
|
|||||||
viper.BindPFlag("staging", command.Flags().Lookup("staging"))
|
viper.BindPFlag("staging", command.Flags().Lookup("staging"))
|
||||||
|
|
||||||
command.Flags().String("domain", "", "Root domain (required)")
|
command.Flags().String("domain", "", "Root domain (required)")
|
||||||
command.MarkFlagRequired("domain")
|
|
||||||
viper.BindPFlag("domain", command.Flags().Lookup("domain"))
|
viper.BindPFlag("domain", command.Flags().Lookup("domain"))
|
||||||
|
|
||||||
command.Flags().String("email", "", "ACME account email address (required)")
|
command.Flags().String("email", "", "ACME account email address (required)")
|
||||||
command.MarkFlagRequired("email")
|
|
||||||
viper.BindPFlag("email", command.Flags().Lookup("email"))
|
viper.BindPFlag("email", command.Flags().Lookup("email"))
|
||||||
|
|
||||||
command.Flags().String("nameservers", "", "List of nameservers separated by commas")
|
command.Flags().String("nameservers", "", "List of nameservers separated by commas (required)")
|
||||||
command.MarkFlagRequired("nameservers")
|
viper.BindPFlag("nameservers", command.Flags().Lookup("nameservers"))
|
||||||
|
|
||||||
if err := command.Execute(); err != nil {
|
if err := command.Execute(); err != nil {
|
||||||
utils.Logger.Fatal().Err(err).Msg("")
|
utils.Logger.Fatal().Err(err).Msg("")
|
||||||
|
27
compose.yml
27
compose.yml
@ -1,14 +1,19 @@
|
|||||||
services:
|
services:
|
||||||
local-ip.sh:
|
local-ip.sh:
|
||||||
image: local-ip.sh
|
image: local-ip.sh
|
||||||
build: .
|
build: .
|
||||||
volumes:
|
volumes:
|
||||||
- lego:/local-ip/.lego
|
- lego:/local-ip/.lego
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
environment:
|
||||||
- 53:53/udp
|
XIP_DOMAIN: "local-ip.sh"
|
||||||
- 80:80/tcp
|
XIP_EMAIL: "admin@local-ip.sh"
|
||||||
- 443:443/tcp
|
XIP_NAMESERVERS: "137.66.40.11,137.66.40.12"
|
||||||
|
# XIP_STAGING: true
|
||||||
|
ports:
|
||||||
|
- 53:53/udp
|
||||||
|
- 80:80/tcp
|
||||||
|
- 443:443/tcp
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
lego:
|
lego:
|
||||||
|
9
fly.toml
9
fly.toml
@ -1,8 +1,3 @@
|
|||||||
# fly.toml app configuration file generated for local-ip-ancient-glade-4376 on 2023-11-29T11:43:10+01:00
|
|
||||||
#
|
|
||||||
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
|
|
||||||
#
|
|
||||||
|
|
||||||
app = "local-ip"
|
app = "local-ip"
|
||||||
primary_region = "ams"
|
primary_region = "ams"
|
||||||
kill_signal = "SIGINT"
|
kill_signal = "SIGINT"
|
||||||
@ -14,7 +9,9 @@ auto_rollback = true
|
|||||||
[build]
|
[build]
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
PORT = "53"
|
XIP_DOMAIN = "local-ip.sh"
|
||||||
|
XIP_EMAIL = "admin@local-ip.sh"
|
||||||
|
XIP_NAMESERVERS = "137.66.40.11,137.66.40.12" # fly.io edge-only ip addresses, see https://community.fly.io/t/custom-domains-certificate-is-stuck-on-awaiting-configuration/8329
|
||||||
|
|
||||||
[mounts]
|
[mounts]
|
||||||
source = "lego"
|
source = "lego"
|
||||||
|
5
go.mod
5
go.mod
@ -3,9 +3,12 @@ module local-ip.sh
|
|||||||
go 1.22
|
go 1.22
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
|
||||||
github.com/go-acme/lego/v4 v4.10.1
|
github.com/go-acme/lego/v4 v4.10.1
|
||||||
github.com/miekg/dns v1.1.57
|
github.com/miekg/dns v1.1.57
|
||||||
github.com/rs/zerolog v1.33.0
|
github.com/rs/zerolog v1.33.0
|
||||||
|
github.com/spf13/cobra v1.8.1
|
||||||
|
github.com/spf13/viper v1.19.0
|
||||||
golang.org/x/net v0.23.0
|
golang.org/x/net v0.23.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
)
|
)
|
||||||
@ -26,9 +29,7 @@ require (
|
|||||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
github.com/spf13/afero v1.11.0 // indirect
|
github.com/spf13/afero v1.11.0 // indirect
|
||||||
github.com/spf13/cast v1.6.0 // indirect
|
github.com/spf13/cast v1.6.0 // indirect
|
||||||
github.com/spf13/cobra v1.8.1 // indirect
|
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/spf13/viper v1.19.0 // indirect
|
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
go.uber.org/atomic v1.9.0 // indirect
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
go.uber.org/multierr v1.9.0 // indirect
|
go.uber.org/multierr v1.9.0 // indirect
|
||||||
|
31
go.sum
31
go.sum
@ -1,11 +1,15 @@
|
|||||||
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||||
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
|
github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
github.com/go-acme/lego/v4 v4.10.1 h1:MiJvoBXNdmAwEK/SImyhwZ8ZL4IR0jtWDD1wST+N138=
|
github.com/go-acme/lego/v4 v4.10.1 h1:MiJvoBXNdmAwEK/SImyhwZ8ZL4IR0jtWDD1wST+N138=
|
||||||
@ -13,12 +17,17 @@ github.com/go-acme/lego/v4 v4.10.1/go.mod h1:EMbf0Jmqwv94nJ5WL9qWnSXIBZnvsS9gNyp
|
|||||||
github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
|
github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
|
||||||
github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
|
github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
@ -34,9 +43,11 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
|
|||||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||||
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||||
@ -65,8 +76,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
|||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
@ -78,8 +87,6 @@ go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
|||||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
|
||||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||||
@ -87,12 +94,10 @@ golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqR
|
|||||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
|
||||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -101,14 +106,14 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
|
@ -2,8 +2,11 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -45,8 +48,9 @@ func registerHandlers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func serveHttp() *http.Server {
|
func serveHttp() *http.Server {
|
||||||
utils.Logger.Info().Msg("Starting up HTTP server on :80")
|
config := utils.GetConfig()
|
||||||
httpServer := &http.Server{Addr: ":http"}
|
httpServer := &http.Server{Addr: fmt.Sprintf(":%d", config.HttpPort)}
|
||||||
|
utils.Logger.Info().Str("http_address", httpServer.Addr).Msg("Starting up HTTP server")
|
||||||
go func() {
|
go func() {
|
||||||
err := httpServer.ListenAndServe()
|
err := httpServer.ListenAndServe()
|
||||||
if err != http.ErrServerClosed {
|
if err != http.ErrServerClosed {
|
||||||
@ -84,22 +88,40 @@ func killServer(httpServer *http.Server) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func redirectHttpToHttps() {
|
func redirectHttpToHttps() {
|
||||||
utils.Logger.Info().Msg("Redirecting HTTP traffic from :80 to HTTPS :443")
|
config := utils.GetConfig()
|
||||||
httpServer := &http.Server{
|
httpServer := &http.Server{
|
||||||
Addr: ":http",
|
Addr: fmt.Sprintf(":%d", config.HttpPort),
|
||||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
url := r.URL
|
url := r.URL
|
||||||
|
host := r.Host
|
||||||
|
|
||||||
|
// Strip the port from the host if present
|
||||||
|
if strings.Contains(host, ":") {
|
||||||
|
hostWithoutPort, _, err := net.SplitHostPort(host)
|
||||||
|
if err != nil {
|
||||||
|
utils.Logger.Error().Err(err).Msg("Failed to split host and port")
|
||||||
|
} else {
|
||||||
|
host = hostWithoutPort
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add the HTTPS port only if it's not 443
|
||||||
|
if config.HttpsPort != 443 {
|
||||||
|
host = net.JoinHostPort(host, strconv.FormatUint(uint64(config.HttpsPort), 10))
|
||||||
|
}
|
||||||
|
|
||||||
url.Host = r.Host
|
url.Host = r.Host
|
||||||
url.Scheme = "https"
|
url.Scheme = "https"
|
||||||
http.Redirect(w, r, url.String(), http.StatusMovedPermanently)
|
http.Redirect(w, r, url.String(), http.StatusMovedPermanently)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
utils.Logger.Info().Str("http_address", httpServer.Addr).Msg("Redirecting HTTP traffic to HTTPS")
|
||||||
go httpServer.ListenAndServe()
|
go httpServer.ListenAndServe()
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveHttps() {
|
func serveHttps() {
|
||||||
utils.Logger.Info().Msg("Starting up HTTPS server on :443")
|
config := utils.GetConfig()
|
||||||
httpsServer := &http.Server{Addr: ":https"}
|
httpsServer := &http.Server{Addr: fmt.Sprintf(":%d", config.HttpsPort)}
|
||||||
|
utils.Logger.Info().Str("https_address", httpsServer.Addr).Msg("Starting up HTTPS server")
|
||||||
go httpsServer.ListenAndServeTLS("./.lego/certs/root/server.pem", "./.lego/certs/root/server.key")
|
go httpsServer.ListenAndServeTLS("./.lego/certs/root/server.pem", "./.lego/certs/root/server.key")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
105
xip/records.go
105
xip/records.go
@ -1,11 +1,9 @@
|
|||||||
package xip
|
package xip
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
"local-ip.sh/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type hardcodedRecord struct {
|
type hardcodedRecord struct {
|
||||||
@ -17,41 +15,8 @@ type hardcodedRecord struct {
|
|||||||
SRV *dns.SRV
|
SRV *dns.SRV
|
||||||
}
|
}
|
||||||
|
|
||||||
var config = utils.GetConfig()
|
var records = map[string]hardcodedRecord{
|
||||||
var hardcodedRecords = map[string]hardcodedRecord{
|
// additional records I set up to host emails, feel free to change or remove them for your own needs
|
||||||
// TODO: maybe --nameservers ns1.local-ip.sh.=137.66.40.11,ns2.local-ip.sh.=137.66.40.12
|
|
||||||
fmt.Sprintf("ns.%s.", config.Domain): {
|
|
||||||
// record holding ip addresses of ns1 and ns2
|
|
||||||
A: []net.IP{
|
|
||||||
net.IPv4(137, 66, 40, 11),
|
|
||||||
net.IPv4(137, 66, 40, 12),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
fmt.Sprintf("ns1.%s.", config.Domain): {
|
|
||||||
A: []net.IP{
|
|
||||||
net.IPv4(137, 66, 40, 11), // fly.io edge-only ip address, see https://community.fly.io/t/custom-domains-certificate-is-stuck-on-awaiting-configuration/8329
|
|
||||||
},
|
|
||||||
},
|
|
||||||
fmt.Sprintf("ns2.%s.", config.Domain): {
|
|
||||||
A: []net.IP{
|
|
||||||
net.IPv4(137, 66, 40, 12), // fly.io edge-only ip address #2
|
|
||||||
},
|
|
||||||
},
|
|
||||||
fmt.Sprintf("%s.", config.Domain): {
|
|
||||||
// same as ns.local-ip.sh, it's the same machine :)
|
|
||||||
A: []net.IP{
|
|
||||||
net.IPv4(137, 66, 40, 11),
|
|
||||||
net.IPv4(137, 66, 40, 12),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
fmt.Sprintf("_acme-challenge.%s.", config.Domain): {
|
|
||||||
// will be filled in later when requesting the wildcard certificate
|
|
||||||
TXT: []string{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// additional records I set up to host emails, feel free to change or remove them for your own needs
|
|
||||||
var extraRecords = map[string]hardcodedRecord{
|
|
||||||
"local-ip.sh.": {
|
"local-ip.sh.": {
|
||||||
TXT: []string{"v=spf1 include:capsulecorp.dev ~all"},
|
TXT: []string{"v=spf1 include:capsulecorp.dev ~all"},
|
||||||
MX: []*dns.MX{
|
MX: []*dns.MX{
|
||||||
@ -85,69 +50,3 @@ var extraRecords = map[string]hardcodedRecord{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
var records = mergeRecords(hardcodedRecords, extraRecords)
|
|
||||||
|
|
||||||
func mergeRecords(a, b map[string]hardcodedRecord) map[string]hardcodedRecord {
|
|
||||||
result := make(map[string]hardcodedRecord)
|
|
||||||
for k, v := range a {
|
|
||||||
result[k] = v
|
|
||||||
}
|
|
||||||
for k, v := range b {
|
|
||||||
if r, ok := result[k]; ok {
|
|
||||||
result[k] = hardcodedRecord{
|
|
||||||
A: uniqueIPs(append(r.A, v.A...)),
|
|
||||||
AAAA: uniqueIPs(append(r.AAAA, v.AAAA...)),
|
|
||||||
TXT: uniqueStrings(append(r.TXT, v.TXT...)),
|
|
||||||
MX: uniqueMX(append(r.MX, v.MX...)),
|
|
||||||
CNAME: uniqueStrings(append(r.CNAME, v.CNAME...)),
|
|
||||||
SRV: firstNonNil(r.SRV, v.SRV),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func uniqueIPs(ips []net.IP) []net.IP {
|
|
||||||
seen := make(map[string]bool)
|
|
||||||
result := []net.IP{}
|
|
||||||
for _, ip := range ips {
|
|
||||||
if !seen[ip.String()] {
|
|
||||||
seen[ip.String()] = true
|
|
||||||
result = append(result, ip)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func uniqueStrings(strs []string) []string {
|
|
||||||
seen := make(map[string]bool)
|
|
||||||
result := []string{}
|
|
||||||
for _, str := range strs {
|
|
||||||
if !seen[str] {
|
|
||||||
seen[str] = true
|
|
||||||
result = append(result, str)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func uniqueMX(mxs []*dns.MX) []*dns.MX {
|
|
||||||
seen := make(map[string]uint16)
|
|
||||||
result := []*dns.MX{}
|
|
||||||
for _, mx := range mxs {
|
|
||||||
if pref, exists := seen[mx.Mx]; !exists || pref > mx.Preference {
|
|
||||||
seen[mx.Mx] = mx.Preference
|
|
||||||
result = append(result, mx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func firstNonNil[T any](a, b *T) *T {
|
|
||||||
if a != nil {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
50
xip/xip.go
50
xip/xip.go
@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
type Xip struct {
|
type Xip struct {
|
||||||
server dns.Server
|
server dns.Server
|
||||||
nameServers []*dns.NS
|
nameServers []string
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -25,6 +25,7 @@ var (
|
|||||||
|
|
||||||
func (xip *Xip) SetTXTRecord(fqdn string, value string) {
|
func (xip *Xip) SetTXTRecord(fqdn string, value string) {
|
||||||
utils.Logger.Debug().Str("fqdn", fqdn).Str("value", value).Msg("Trying to set TXT record")
|
utils.Logger.Debug().Str("fqdn", fqdn).Str("value", value).Msg("Trying to set TXT record")
|
||||||
|
config := utils.GetConfig()
|
||||||
if fqdn != fmt.Sprintf("_acme-challenge.%s.", config.Domain) {
|
if fqdn != fmt.Sprintf("_acme-challenge.%s.", config.Domain) {
|
||||||
utils.Logger.Debug().Msg("Not allowed, abort")
|
utils.Logger.Debug().Msg("Not allowed, abort")
|
||||||
return
|
return
|
||||||
@ -38,6 +39,7 @@ func (xip *Xip) SetTXTRecord(fqdn string, value string) {
|
|||||||
|
|
||||||
func (xip *Xip) UnsetTXTRecord(fqdn string) {
|
func (xip *Xip) UnsetTXTRecord(fqdn string) {
|
||||||
utils.Logger.Debug().Str("fqdn", fqdn).Msg("Trying to set TXT record")
|
utils.Logger.Debug().Str("fqdn", fqdn).Msg("Trying to set TXT record")
|
||||||
|
config := utils.GetConfig()
|
||||||
if fqdn != fmt.Sprintf("_acme-challenge.%s.", config.Domain) {
|
if fqdn != fmt.Sprintf("_acme-challenge.%s.", config.Domain) {
|
||||||
utils.Logger.Debug().Msg("Not allowed, abort")
|
utils.Logger.Debug().Msg("Not allowed, abort")
|
||||||
return
|
return
|
||||||
@ -145,10 +147,10 @@ func (xip *Xip) handleNS(question dns.Question, message *dns.Msg) {
|
|||||||
Rrtype: dns.TypeNS,
|
Rrtype: dns.TypeNS,
|
||||||
Class: dns.ClassINET,
|
Class: dns.ClassINET,
|
||||||
},
|
},
|
||||||
Ns: ns.Ns,
|
Ns: ns,
|
||||||
})
|
})
|
||||||
|
|
||||||
additionals = append(additionals, xip.fqdnToA(ns.Ns)...)
|
additionals = append(additionals, xip.fqdnToA(ns)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, record := range nameServers {
|
for _, record := range nameServers {
|
||||||
@ -257,7 +259,15 @@ func (xip *Xip) handleSOA(question dns.Question, message *dns.Msg) {
|
|||||||
message.Answer = append(message.Answer, xip.soaRecord(question))
|
message.Answer = append(message.Answer, xip.soaRecord(question))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func emailToRname(email string) string {
|
||||||
|
parts := strings.SplitN(email, "@", 2)
|
||||||
|
localPart := strings.ReplaceAll(parts[0], ".", "\\.")
|
||||||
|
domain := parts[1]
|
||||||
|
return localPart + "." + domain + "."
|
||||||
|
}
|
||||||
|
|
||||||
func (xip *Xip) soaRecord(question dns.Question) *dns.SOA {
|
func (xip *Xip) soaRecord(question dns.Question) *dns.SOA {
|
||||||
|
config := utils.GetConfig()
|
||||||
soa := new(dns.SOA)
|
soa := new(dns.SOA)
|
||||||
soa.Hdr = dns.RR_Header{
|
soa.Hdr = dns.RR_Header{
|
||||||
Name: question.Name,
|
Name: question.Name,
|
||||||
@ -266,8 +276,8 @@ func (xip *Xip) soaRecord(question dns.Question) *dns.SOA {
|
|||||||
Ttl: uint32((time.Minute * 5).Seconds()),
|
Ttl: uint32((time.Minute * 5).Seconds()),
|
||||||
Rdlength: 0,
|
Rdlength: 0,
|
||||||
}
|
}
|
||||||
soa.Ns = xip.nameServers[0].Ns
|
soa.Ns = xip.nameServers[0]
|
||||||
soa.Mbox = config.Email
|
soa.Mbox = emailToRname(config.Email)
|
||||||
soa.Serial = 2024072200
|
soa.Serial = 2024072200
|
||||||
soa.Refresh = uint32((time.Minute * 15).Seconds())
|
soa.Refresh = uint32((time.Minute * 15).Seconds())
|
||||||
soa.Retry = uint32((time.Minute * 15).Seconds())
|
soa.Retry = uint32((time.Minute * 15).Seconds())
|
||||||
@ -321,6 +331,7 @@ func (xip *Xip) handleDnsRequest(response dns.ResponseWriter, request *dns.Msg)
|
|||||||
|
|
||||||
error := response.WriteMsg(message)
|
error := response.WriteMsg(message)
|
||||||
if error != nil {
|
if error != nil {
|
||||||
|
utils.Logger.Debug().Msg(message.String())
|
||||||
utils.Logger.Error().Err(error).Str("message", message.String()).Msg("Error responding to query")
|
utils.Logger.Error().Err(error).Str("message", message.String()).Msg("Error responding to query")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -335,6 +346,7 @@ func (xip *Xip) StartServer() {
|
|||||||
err := xip.server.ListenAndServe()
|
err := xip.server.ListenAndServe()
|
||||||
defer xip.server.Shutdown()
|
defer xip.server.Shutdown()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
utils.Logger.Fatal().Err(err).Msg("Failed to start DNS server")
|
||||||
if strings.Contains(err.Error(), "fly-global-services: no such host") {
|
if strings.Contains(err.Error(), "fly-global-services: no such host") {
|
||||||
// we're not running on fly, bind to 0.0.0.0 instead
|
// we're not running on fly, bind to 0.0.0.0 instead
|
||||||
port := strings.Split(xip.server.Addr, ":")[1]
|
port := strings.Split(xip.server.Addr, ":")[1]
|
||||||
@ -349,16 +361,36 @@ func (xip *Xip) StartServer() {
|
|||||||
|
|
||||||
utils.Logger.Fatal().Err(err).Msg("Failed to start DNS server")
|
utils.Logger.Fatal().Err(err).Msg("Failed to start DNS server")
|
||||||
}
|
}
|
||||||
utils.Logger.Info().Str("dns_address", xip.server.Addr).Msg("DNS server listening")
|
utils.Logger.Info().Str("dns_address", xip.server.Addr).Msg("Starting up DNS server")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (xip *Xip) initHardcodedRecords() {
|
||||||
|
config := utils.GetConfig()
|
||||||
|
rootDomainARecords := []net.IP{}
|
||||||
|
|
||||||
|
for i, ns := range config.NameServers {
|
||||||
|
name := fmt.Sprintf("ns%d.%s.", i+1, config.Domain)
|
||||||
|
ip := net.ParseIP(ns)
|
||||||
|
|
||||||
|
rootDomainARecords = append(rootDomainARecords, ip)
|
||||||
|
entry := records[name]
|
||||||
|
entry.A = append(records[name].A, ip)
|
||||||
|
records[name] = entry
|
||||||
|
|
||||||
|
xip.nameServers = append(xip.nameServers, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
records[fmt.Sprintf("%s.", config.Domain)] = hardcodedRecord{A: rootDomainARecords}
|
||||||
|
|
||||||
|
// will be filled in later when requesting the wildcard certificate
|
||||||
|
records[fmt.Sprintf("_acme-challenge.%s.", config.Domain)] = hardcodedRecord{TXT: []string{}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewXip() (xip *Xip) {
|
func NewXip() (xip *Xip) {
|
||||||
config := utils.GetConfig()
|
config := utils.GetConfig()
|
||||||
xip = &Xip{}
|
xip = &Xip{}
|
||||||
|
|
||||||
for _, ns := range config.NameServers {
|
xip.initHardcodedRecords()
|
||||||
xip.nameServers = append(xip.nameServers, &dns.NS{Ns: ns})
|
|
||||||
}
|
|
||||||
|
|
||||||
xip.server = dns.Server{
|
xip.server = dns.Server{
|
||||||
Addr: fmt.Sprintf(":%d", config.DnsPort),
|
Addr: fmt.Sprintf(":%d", config.DnsPort),
|
||||||
|
Loading…
Reference in New Issue
Block a user