env var working, got some validation done before running the cli

This commit is contained in:
m5r 2024-07-26 00:56:24 +02:00
parent 92ad51d001
commit 3a65254902
Signed by: mokhtar
GPG Key ID: 1509B54946D08A95
9 changed files with 159 additions and 190 deletions

View File

@ -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."]

View File

@ -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("")

View File

@ -5,6 +5,11 @@ services:
volumes: volumes:
- lego:/local-ip/.lego - lego:/local-ip/.lego
restart: unless-stopped restart: unless-stopped
environment:
XIP_DOMAIN: "local-ip.sh"
XIP_EMAIL: "admin@local-ip.sh"
XIP_NAMESERVERS: "137.66.40.11,137.66.40.12"
# XIP_STAGING: true
ports: ports:
- 53:53/udp - 53:53/udp
- 80:80/tcp - 80:80/tcp

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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")
} }

View File

@ -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
}

View File

@ -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),