Initial import

This commit is contained in:
maze 2024-07-24 15:38:56 +02:00
parent dbc4671ddc
commit a0bc0df32a
14 changed files with 736 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Don't check in private key files
*.key

51
cmd/update-ip/main.go Normal file
View File

@ -0,0 +1,51 @@
package main
import (
"flag"
updateip "git.maze.io/wijnand/update-ip"
log "github.com/sirupsen/logrus"
)
func main() {
configFile := flag.String("config", "", "configuration file")
debugFlag := flag.Bool("debug", false, "enable debug messages")
traceFlag := flag.Bool("trace", false, "enable trace messages")
flag.Parse()
if *traceFlag {
log.SetLevel(log.TraceLevel)
} else if *debugFlag {
log.SetLevel(log.DebugLevel)
}
c, err := updateip.Load(*configFile)
if err != nil {
log.WithError(err).Fatal("failed to configure")
}
ip, err := c.Resolver.CurrentIP()
if err != nil {
log.WithError(err).Fatal("failed to resolve current IP")
}
log.WithField("ip", ip).Info("resolved current IP")
if !c.Resolver.IsAllowed(ip) {
log.WithField("ip", ip).Fatal("not allowed by ACL")
}
for _, domain := range c.Domain {
log := log.WithField("domain", domain.Name)
log.Info("checking domain")
if len(domain.Update) == 0 {
log.Warn("no records to update!")
continue
}
for _, record := range domain.Update {
if err := domain.Provider.UpdateIP(domain.Name, record, ip); err != nil {
log.WithError(err).Error("update failed!")
}
}
}
}

93
config.go Normal file
View File

@ -0,0 +1,93 @@
package updateip
import (
"fmt"
"net"
"github.com/hashicorp/hcl/v2/hclsimple"
log "github.com/sirupsen/logrus"
)
func Load(name string) (*Config, error) {
var (
config Config
err error
)
log.WithField("config", name).Debug("loading configuration file")
if err = hclsimple.DecodeFile(name, nil, &config); err != nil {
return nil, err
}
providers := make(map[string]Provider)
for _, v := range config.Provider {
if providers[v.Name], err = NewProvider(v); err != nil {
return nil, fmt.Errorf("error configuring provider %q: %w", v.Name, err)
}
}
for _, v := range config.Domain {
if p, ok := providers[v.ProviderName]; ok {
v.Provider = p
} else {
return nil, fmt.Errorf("provider %q in domain %q is not configured", v.ProviderName, v.Name)
}
if len(v.Update) == 0 {
v.Update = append(v.Update, "@")
}
}
return &config, nil
}
type Config struct {
Resolver ResolverConfig `hcl:"resolver,block"`
Domain []*DomainConfig `hcl:"domain,block"`
Provider []*ProviderConfig `hcl:"provider,block"`
}
type ResolverConfig struct {
Permit []string `hcl:"permit"`
}
func (r ResolverConfig) CurrentIP() (net.IP, error) {
return NewResolver().CurrentIP()
}
func (r ResolverConfig) IsAllowed(ip net.IP) bool {
if len(r.Permit) == 0 {
// Fail open if no ACL is configured.
log.WithField("ip", ip.String()).Debug("IP allowed by resolver; no ACL")
return true
}
for _, v := range r.Permit {
if _, ipnet, err := net.ParseCIDR(v); err == nil {
if ipnet.Contains(ip) {
log.WithFields(log.Fields{
"ip": ip.String(),
"range": ipnet.String(),
}).Debug("IP allowed by resolver ACL")
return true
}
}
}
log.WithField("ip", ip.String()).Warn("IP not allowed by resolver ACL")
return false
}
type DomainConfig struct {
Name string `hcl:"name,label"`
ProviderName string `hcl:"provider"`
Provider Provider ``
Update []string `hcl:"update,optional"`
}
type ProviderConfig struct {
Name string `hcl:"name,label"`
Type string
Username string `hcl:"username"`
PrivateKey string `hcl:"private_key"`
}

39
fqdn.go Normal file
View File

@ -0,0 +1,39 @@
package updateip
import "strings"
// Canonicalize a DNS record.
func Canonicalize(domainName, recordName string) string {
if recordName == "@" {
return ToFqdn(domainName)
} else if strings.HasSuffix(recordName, ".@") {
return ToFqdn(strings.TrimSuffix(recordName, "@") + domainName)
}
return ToFqdn(recordName)
}
// IsFqdn checks if the label is a full-qualified name.
func IsFqdn(name string) bool {
return strings.HasSuffix(name, ".")
}
// ToFqdn converts the name into a fqdn appending a trailing dot.
func ToFqdn(name string) string {
if name == "@" {
return name
}
n := len(name)
if n == 0 || name[n-1] == '.' {
return name
}
return name + "."
}
// UnFqdn converts the fqdn into a name removing the trailing dot.
func UnFqdn(name string) string {
n := len(name)
if n != 0 && name[n-1] == '.' {
return name[:n-1]
}
return name
}

64
fqdn_test.go Normal file
View File

@ -0,0 +1,64 @@
package updateip
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestToFqdn(t *testing.T) {
testCases := []struct {
desc string
domain string
expected string
}{
{
desc: "simple",
domain: "foo.example.com",
expected: "foo.example.com.",
},
{
desc: "already FQDN",
domain: "foo.example.com.",
expected: "foo.example.com.",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
fqdn := ToFqdn(test.domain)
assert.Equal(t, test.expected, fqdn)
})
}
}
func TestUnFqdn(t *testing.T) {
testCases := []struct {
desc string
fqdn string
expected string
}{
{
desc: "simple",
fqdn: "foo.example.",
expected: "foo.example",
},
{
desc: "already domain",
fqdn: "foo.example",
expected: "foo.example",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
domain := UnFqdn(test.fqdn)
assert.Equal(t, test.expected, domain)
})
}
}

27
go.mod Normal file
View File

@ -0,0 +1,27 @@
module git.maze.io/wijnand/update-ip
go 1.22.3
require (
github.com/hashicorp/hcl/v2 v2.21.0
github.com/sirupsen/logrus v1.9.3
github.com/transip/gotransip/v6 v6.25.0
)
require (
github.com/agext/levenshtein v1.2.1 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/transip/gotransip v5.8.2+incompatible // indirect
github.com/zclconf/go-cty v1.13.0 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/tools v0.6.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

51
go.sum Normal file
View File

@ -0,0 +1,51 @@
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
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/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hashicorp/hcl/v2 v2.21.0 h1:lve4q/o/2rqwYOgUg3y3V2YPyD1/zkCLGjIV74Jit14=
github.com/hashicorp/hcl/v2 v2.21.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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/transip/gotransip v5.8.2+incompatible h1:aNJhw/w/3QBqFcHAIPz1ytoK5FexeMzbUCGrrhWr3H0=
github.com/transip/gotransip v5.8.2+incompatible/go.mod h1:uacMoJVmrfOcscM4Bi5NVg708b7c6rz2oDTWqa7i2Ic=
github.com/transip/gotransip/v6 v6.25.0 h1:/H+SjMq/9HNZ0/maE1OLhJpxLaCGHsxq0PWaMPJHxK4=
github.com/transip/gotransip/v6 v6.25.0/go.mod h1:x0/RWGRK/zob817O3tfO2xhFoP1vu8YOHORx6Jpk80s=
github.com/zclconf/go-cty v1.13.0 h1:It5dfKTTZHe9aeppbNOda3mN7Ag7sg6QkBNm6TkyFa0=
github.com/zclconf/go-cty v1.13.0/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

66
label.go Normal file
View File

@ -0,0 +1,66 @@
package updateip
import (
"strings"
"unicode/utf8"
)
// CompressLabel returns the smallest possible subdomain label for the provided record against the domain.
func CompressLabel(domainName, recordName string) string {
domainName = UnFqdn(domainName)
recordName = UnFqdn(recordName)
if strings.EqualFold(domainName, recordName) {
return "@"
} else if i := indexFold(recordName, "."+domainName); i > -1 {
return recordName[:i]
}
return recordName
}
// ExapandLabel gives the full DNS label for the (abbreviated) record.
func ExapandLabel(domainName, recordName string) string {
if strings.EqualFold(domainName, recordName) {
return recordName
} else if IsFqdn(recordName) {
return recordName
} else if recordName == "@" {
return domainName
} else if i := strings.LastIndex(recordName, ".@"); i > -1 {
return recordName[:i] + "." + domainName
}
return recordName + "." + domainName
}
// indexFold returns the index of the first instance of substr in s (case insensitive), or -1 if substr is not present in s.
func indexFold(s, substr string) int {
ns := len(s)
nb := len(substr)
if ns < nb {
return -1
}
if nb == 0 {
return 0
}
if ns == nb {
if strings.EqualFold(s, substr) {
return 0
}
return -1
}
l := ns - nb
for i := 0; i <= l; {
src := s[i : i+nb]
if strings.EqualFold(src, substr) {
return i
}
_, z := utf8.DecodeRuneInString(src)
i += z
}
return -1
}
// hasSuffixFold Tests if the string s ends with the specified suffix (case insensitive).
func hasSuffixFold(s, suffix string) bool {
return len(s) >= len(suffix) && strings.EqualFold(s[len(s)-len(suffix):], suffix)
}

91
label_test.go Normal file
View File

@ -0,0 +1,91 @@
package updateip
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCompressLabel(t *testing.T) {
testCases := []struct {
desc string
domain, record string
expected string
}{
{
"same",
"example.org",
"example.org",
"@",
},
{
"same_fqdn",
"example.org.",
"example.org",
"@",
},
{
"simple",
"example.org",
"www.example.org",
"www",
},
{
"unrelated",
"example.org",
"example.net",
"example.net",
},
}
for _, test := range testCases {
t.Run(test.desc, func(it *testing.T) {
it.Parallel()
result := CompressLabel(test.domain, test.record)
assert.Equal(it, test.expected, result)
})
}
}
func TestExpandLabel(t *testing.T) {
testCases := []struct {
desc string
domain, record string
expected string
}{
{
"same",
"example.org",
"@",
"example.org",
},
{
"simple",
"example.org",
"www",
"www.example.org",
},
{
"unrelated",
"example.org",
"example.net",
"example.net.example.org",
},
{
"using_at",
"example.org",
"www.@",
"www.example.org",
},
}
for _, test := range testCases {
t.Run(test.desc, func(it *testing.T) {
it.Parallel()
result := ExapandLabel(test.domain, test.record)
assert.Equal(it, test.expected, result)
})
}
}

39
provider.go Normal file
View File

@ -0,0 +1,39 @@
package updateip
import (
"errors"
"fmt"
"net"
"strings"
"time"
log "github.com/sirupsen/logrus"
)
const DefaultTTL = 5 * time.Minute
type Provider interface {
UpdateIP(domain, name string, ip net.IP) error
}
func NewProvider(config *ProviderConfig) (Provider, error) {
if config == nil {
return nil, errors.New("provider: config is nil")
}
if config.Type == "" {
config.Type = config.Name
}
log.WithFields(log.Fields{
"name": config.Name,
"type": config.Type,
}).Debug("configuring provider")
switch strings.ToLower(config.Type) {
case "transip":
return NewTransIP(config)
default:
return nil, fmt.Errorf("provider %s: unsupported type %q", config.Name, config.Type)
}
}

91
provider_transip.go Normal file
View File

@ -0,0 +1,91 @@
package updateip
import (
"net"
"strings"
log "github.com/sirupsen/logrus"
"github.com/transip/gotransip/v6"
transipdomain "github.com/transip/gotransip/v6/domain"
)
type transipProvider struct {
repo transipdomain.Repository
}
func NewTransIP(config *ProviderConfig) (Provider, error) {
client, err := gotransip.NewClient(gotransip.ClientConfiguration{
AccountName: config.Username,
PrivateKeyPath: config.PrivateKey,
})
if err != nil {
return nil, err
}
return &transipProvider{
repo: transipdomain.Repository{Client: client},
}, nil
}
func (p *transipProvider) UpdateIP(domain, name string, ip net.IP) error {
domainName := UnFqdn(domain)
entries, err := p.repo.GetDNSEntries(domainName)
if err != nil {
return err
}
entryName := CompressLabel(domainName, UnFqdn(name))
for _, entry := range entries {
log := log.WithFields(log.Fields{
"domain": domainName,
"name": entry.Name,
"type": entry.Type,
"ttl": entry.Expire,
"content": entry.Content,
})
log.Trace("checking DNS record")
if strings.EqualFold(ExapandLabel(domainName, entryName), ExapandLabel(domainName, entry.Name)) {
switch {
case IsLabel(entry.Type):
if entry.Content != ip.String() {
log.WithField("content", ip.String()).Info("updating DNS record content")
return p.repo.UpdateDNSEntry(domainName, entry)
}
log.Debug("not updating DNS record; already up-to-date!")
return nil
case IsCanonicalName(entry.Type):
log.Info("removing DNS record")
if err = p.repo.RemoveDNSEntry(domainName, entry); err != nil {
return err
}
}
}
}
// No entry found, create one
entry := transipdomain.DNSEntry{
Name: entryName,
Type: "A",
Content: ip.String(),
Expire: int(DefaultTTL.Seconds()),
}
log.WithFields(log.Fields{
"name": entry.Name,
"type": "A",
"new": ip.String(),
"expire": entry.Expire,
}).Info("creating DNS record")
return p.repo.AddDNSEntry(domainName, entry)
}
// IsLabel check if the DNS record type is a DNS label (A-record).
func IsLabel(recordType string) bool {
return strings.EqualFold(recordType, "A")
}
// IsCanonicalName checks if the DNS record type is a DNS canonical name (CNAME record).
func IsCanonicalName(recordType string) bool {
return strings.EqualFold(recordType, "CNAME")
}

33
resolve.go Normal file
View File

@ -0,0 +1,33 @@
package updateip
import (
"io"
"net"
"net/http"
)
type Resolver interface {
CurrentIP() (net.IP, error)
}
func NewResolver() Resolver {
return new(Ipify)
}
type Ipify struct{}
func (Ipify) CurrentIP() (net.IP, error) {
r, err := http.Get("https://api.ipify.org")
if err != nil {
return nil, err
}
defer func() { _ = r.Body.Close() }()
b, err := io.ReadAll(r.Body)
if err != nil {
return nil, err
}
return net.ParseIP(string(b)), nil
}

13
resolve_test.go Normal file
View File

@ -0,0 +1,13 @@
package updateip
import "testing"
func TestResolveCurrentIP(t *testing.T) {
r := new(Ipify)
v, err := r.CurrentIP()
if err != nil {
t.Error(err)
}
t.Log("current IP:", v)
}

76
update-my-ip.hcl Normal file
View File

@ -0,0 +1,76 @@
resolver {
permit = [
# AS50266 - Odido Netherlands B.V.
"143.177.0.0/16", # Pool for fixed WBA users 65,536
"143.178.0.0/17", # Pool for fixed WBA users 32,768
"143.178.128.0/17", # Pool for fixed WBA users 32,768
"143.178.232.0/24", # Pool for fixed WBA users 256
"143.179.0.0/16", # Tele2 Nederland B.V. 65,536
"185.180.148.0/22", # Odido Netherlands B.V. 1,024
"185.35.112.0/22", # Odido Netherlands B.V. 1,024
"188.88.0.0/14", # Odido Netherlands B.V. 262,144
"188.88.0.0/16", # Pool for mobile internet users 65,536
"188.89.0.0/16", # Pool for mobile internet users 65,536
"188.90.0.0/16", # Pool for mobile internet users 65,536
"188.91.0.0/16", # Pool for mobile internet users 65,536
"195.191.16.0/23", # Odido Netherlands B.V. 512
"31.184.64.0/18", # Odido Netherlands 16,384
"31.187.128.0/17", # Pool for fixed WBA, ODF and VULA users 32,768
"31.20.0.0/16", # Pool for fixed WBA users 65,536
"31.201.0.0/16", # Pool for fixed WBA, ODF and VULA users 65,536
"31.21.0.0/16", # Pool for fixed WBA users 65,536
"37.143.80.0/21", # Odido Netherlands B.V. 2,048
"5.132.0.0/17", # Odido Netherlands B.V. 32,768
"62.166.128.0/17", # Pool for fixed WBA users 32,768
"62.250.0.0/17", # Odido Netherlands 32,768
"62.250.128.0/17", # Pool for fixed WBA users 32,768
"81.59.0.0/17", # Zon internet is one of the largest free ISP in the Netherlands 32,768
"82.172.0.0/17", # Tele2 Consumer is one of the largest ISP\'s in the Netherlands 32,768
"82.174.0.0/16", # Pool for fixed WBA users 65,536
"85.144.0.0/15", # Odido Netherlands B.V. 131,072
"85.146.0.0/17", # Odido Netherlands B.V. 32,768
"85.146.128.0/18", # Odido Netherlands B.V. 16,384
"85.223.0.0/17", # Odido Netherlands 32,768
"87.208.0.0/16", # Pool for fixed WBA users 65,536
"87.209.0.0/16", # Pool for fixed WBA users 65,536
"87.209.180.0/24", # Pool for fixed WBA users 256
"87.210.0.0/16", # Pool for fixed WBA users 65,536
"87.212.0.0/16", # Pool for fixed WBA users 65,536
"92.254.0.0/17", # Odido Netherlands 32,768
"94.157.0.0/16", # Pool for fixed WBA, ODF and VULA users 65,536
"95.98.0.0/15", # Odido Netherlands B.V. 131,072
"95.98.0.0/16", # Pool for mobile internet users 65,536
"95.99.0.0/16", # Pool for mobile internet users 65,536
]
}
#domain "maze.io" {
# provider = "transip"
# update = ["maze.io", "www.maze.io"]
#}
domain "duzzdus.nl" {
provider = "transip"
}
domain "modderman-lenstra.nl" {
provider = "transip"
}
domain "maze.casa" {
provider = "transip"
}
domain "maze.network" {
provider = "transip"
}
domain "maze.io" {
provider = "transip"
update = ["@", "lab.maze.io"]
}
provider "transip" {
username = "tehmaze"
private_key = "testdata/transip.key"
}