mirror of
https://gitlab.durp.info/durfy/apps/durpdns.git
synced 2026-05-07 07:50:33 -05:00
Updated to 3 providers to add more reliability
This commit is contained in:
parent
06c9569e82
commit
03b36127db
1 changed files with 194 additions and 55 deletions
237
main.go
237
main.go
|
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/caarlos0/env/v6"
|
"github.com/caarlos0/env/v6"
|
||||||
"github.com/cloudflare/cloudflare-go/v4"
|
"github.com/cloudflare/cloudflare-go/v4"
|
||||||
|
|
@ -12,11 +13,14 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IPResponse struct {
|
var ipPattern = `^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`
|
||||||
IPAddress string `json:"YourFuckingIPAddress"`
|
|
||||||
|
type WTFIPResponse struct {
|
||||||
|
IP string `json:"YourFuckingIPAddress"`
|
||||||
Location string `json:"YourFuckingLocation"`
|
Location string `json:"YourFuckingLocation"`
|
||||||
Hostname string `json:"YourFuckingHostname"`
|
Hostname string `json:"YourFuckingHostname"`
|
||||||
ISP string `json:"YourFuckingISP"`
|
ISP string `json:"YourFuckingISP"`
|
||||||
|
|
@ -26,10 +30,111 @@ type IPResponse struct {
|
||||||
CountryCode string `json:"YourFuckingCountryCode"`
|
CountryCode string `json:"YourFuckingCountryCode"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IpifyResponse struct {
|
||||||
|
IP string `json:"ip"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpInfoResponse struct {
|
||||||
|
IP string `json:"ip"`
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
City string `json:"city"`
|
||||||
|
Region string `json:"region"`
|
||||||
|
Country string `json:"country"`
|
||||||
|
Loc string `json:"loc"`
|
||||||
|
Org string `json:"org"`
|
||||||
|
Postal string `json:"postal"`
|
||||||
|
Timezone string `json:"timezone"`
|
||||||
|
Readme string `json:"readme"`
|
||||||
|
}
|
||||||
|
type Response struct {
|
||||||
|
IPAddress string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseInterface interface {
|
||||||
|
getIP() Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *WTFIPResponse) getIP() Response {
|
||||||
|
return Response{IPAddress: r.IP}
|
||||||
|
}
|
||||||
|
func (r *IpInfoResponse) getIP() Response {
|
||||||
|
return Response{IPAddress: r.IP}
|
||||||
|
}
|
||||||
|
func (r *IpifyResponse) getIP() Response {
|
||||||
|
return Response{IPAddress: r.IP}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIpifyProvider() *IpProvider {
|
||||||
|
return &IpProvider{
|
||||||
|
url: "https://api.ipify.org?format=json",
|
||||||
|
resp: new(IpifyResponse),
|
||||||
|
client: http.Client{
|
||||||
|
Timeout: 5 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIpInfoProvider() *IpProvider {
|
||||||
|
return &IpProvider{
|
||||||
|
url: "https://ipinfo.io/json",
|
||||||
|
resp: new(IpInfoResponse),
|
||||||
|
client: http.Client{
|
||||||
|
Timeout: 5 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWTFProvider() *IpProvider {
|
||||||
|
return &IpProvider{
|
||||||
|
url: "https://myip.wtf/json",
|
||||||
|
resp: new(WTFIPResponse),
|
||||||
|
client: http.Client{
|
||||||
|
Timeout: 5 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpProvider struct {
|
||||||
|
url string
|
||||||
|
resp interface{}
|
||||||
|
client http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *IpProvider) get() *Response {
|
||||||
|
|
||||||
|
body, err := p.client.Get(p.url)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer body.Body.Close()
|
||||||
|
|
||||||
|
data, err := io.ReadAll(body.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(data, &p.resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := p.resp.(ResponseInterface).getIP()
|
||||||
|
pattern := regexp.MustCompile(ipPattern)
|
||||||
|
|
||||||
|
if !pattern.MatchString(resp.IPAddress) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &resp
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
CloudflareZoneID string `env:"CLOUDFLARE_ZONE_ID"`
|
CloudflareZoneID string `env:"CLOUDFLARE_ZONE_ID"`
|
||||||
CloudFlareAPIKey string `env:"CLOUDFLARE_API_KEY"`
|
CloudFlareAPIKey string `env:"CLOUDFLARE_API_KEY"`
|
||||||
CloudflareEmail string `env:"CLOUDFLARE_EMAIL"`
|
CloudflareEmail string `env:"CLOUDFLARE_EMAIL"`
|
||||||
|
IpProviders []*IpProvider
|
||||||
|
Client *cloudflare.Client
|
||||||
|
Timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
@ -40,7 +145,9 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config := &Config{}
|
config := &Config{
|
||||||
|
Timeout: 5 * time.Second,
|
||||||
|
}
|
||||||
err = env.Parse(config)
|
err = env.Parse(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to load env file")
|
log.Fatal("Failed to load env file")
|
||||||
|
|
@ -52,81 +159,107 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client := cloudflare.NewClient(
|
config.Client = cloudflare.NewClient(
|
||||||
option.WithAPIKey(config.CloudFlareAPIKey),
|
option.WithAPIKey(config.CloudFlareAPIKey),
|
||||||
option.WithAPIEmail(config.CloudflareEmail),
|
option.WithAPIEmail(config.CloudflareEmail),
|
||||||
)
|
)
|
||||||
|
|
||||||
ExistingIP, err := getIP()
|
config.IpProviders = append(
|
||||||
if err != nil {
|
config.IpProviders,
|
||||||
fmt.Println(err)
|
NewWTFProvider(),
|
||||||
return
|
)
|
||||||
}
|
config.IpProviders = append(
|
||||||
|
config.IpProviders,
|
||||||
|
NewIpifyProvider(),
|
||||||
|
)
|
||||||
|
config.IpProviders = append(
|
||||||
|
config.IpProviders,
|
||||||
|
NewIpInfoProvider(),
|
||||||
|
)
|
||||||
|
|
||||||
|
ExistingIP, err := GetIPAddress(config)
|
||||||
|
|
||||||
|
fmt.Printf("The current IP address is: %s\n", ExistingIP)
|
||||||
|
|
||||||
err = updateDNSRecords(
|
err = updateDNSRecords(
|
||||||
client,
|
config,
|
||||||
config.CloudflareZoneID,
|
ExistingIP,
|
||||||
ExistingIP.IPAddress,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Your public IP address is:", ExistingIP.IPAddress)
|
|
||||||
|
|
||||||
do:
|
do:
|
||||||
for {
|
for {
|
||||||
CurrentIP, err := getIP()
|
CurrentIP, err := GetIPAddress(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
continue do
|
continue do
|
||||||
}
|
}
|
||||||
|
|
||||||
if ExistingIP.IPAddress != CurrentIP.IPAddress {
|
if ExistingIP == CurrentIP {
|
||||||
|
time.Sleep(config.Timeout)
|
||||||
|
continue do
|
||||||
|
}
|
||||||
|
|
||||||
ExistingIP = CurrentIP
|
ExistingIP = CurrentIP
|
||||||
fmt.Println(
|
fmt.Printf(
|
||||||
"Your public IP address has updated:",
|
"Your IP address has changed: %s\n",
|
||||||
ExistingIP.IPAddress,
|
CurrentIP,
|
||||||
)
|
)
|
||||||
|
|
||||||
err := updateDNSRecords(
|
err = updateDNSRecords(
|
||||||
client,
|
config,
|
||||||
config.CloudflareZoneID,
|
CurrentIP,
|
||||||
CurrentIP.IPAddress,
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
time.Sleep(config.Timeout)
|
||||||
fmt.Println("Your public IP address has not changed.")
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
continue do
|
continue do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIP() (*IPResponse, error) {
|
func GetIPAddress(config *Config) (string, error) {
|
||||||
|
|
||||||
client := &http.Client{
|
responses := []*Response{}
|
||||||
Timeout: time.Second * 5,
|
|
||||||
}
|
|
||||||
var ip IPResponse
|
|
||||||
resp, err := client.Get("https://myip.wtf/json")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
data, err := io.ReadAll(resp.Body)
|
for _, provider := range config.IpProviders {
|
||||||
if err != nil {
|
resp := provider.get()
|
||||||
return nil, err
|
responses = append(responses, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(data, &ip)
|
// Count the occurrences of each IPAddress
|
||||||
return &ip, err
|
counts := map[string]int{}
|
||||||
|
for _, r := range responses {
|
||||||
|
if r != nil {
|
||||||
|
IP := r.IPAddress
|
||||||
|
if count, ok := counts[IP]; ok {
|
||||||
|
counts[IP] = count + 1
|
||||||
|
} else {
|
||||||
|
counts[IP] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the IPAddress that repeats the most
|
||||||
|
maxCount := 0
|
||||||
|
CurrentIP := ""
|
||||||
|
for IP, count := range counts {
|
||||||
|
if count > maxCount {
|
||||||
|
maxCount = count
|
||||||
|
CurrentIP = IP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern := regexp.MustCompile(ipPattern)
|
||||||
|
|
||||||
|
if !pattern.MatchString(CurrentIP) {
|
||||||
|
return "", errors.New("Did not find a valid IP")
|
||||||
|
}
|
||||||
|
|
||||||
|
return CurrentIP, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDNSRecords(
|
func getDNSRecords(
|
||||||
|
|
@ -154,17 +287,23 @@ func getDNSRecords(
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateDNSRecords(
|
func updateDNSRecords(
|
||||||
client *cloudflare.Client,
|
config *Config,
|
||||||
zoneID string,
|
|
||||||
ipAddress string,
|
ipAddress string,
|
||||||
) error {
|
) error {
|
||||||
records, err := getDNSRecords(client, zoneID)
|
records, err := getDNSRecords(
|
||||||
|
config.Client,
|
||||||
|
config.CloudflareZoneID,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, record := range *records {
|
for _, record := range *records {
|
||||||
|
|
||||||
|
if record.Content == ipAddress {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
NewDNS := dns.ARecordParam{
|
NewDNS := dns.ARecordParam{
|
||||||
Comment: cloudflare.F(record.Comment),
|
Comment: cloudflare.F(record.Comment),
|
||||||
Content: cloudflare.F(ipAddress),
|
Content: cloudflare.F(ipAddress),
|
||||||
|
|
@ -174,9 +313,9 @@ func updateDNSRecords(
|
||||||
Type: cloudflare.F(dns.ARecordTypeA),
|
Type: cloudflare.F(dns.ARecordTypeA),
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = client.DNS.Records.Edit(
|
_, err = config.Client.DNS.Records.Edit(
|
||||||
context.TODO(), record.ID, dns.RecordEditParams{
|
context.TODO(), record.ID, dns.RecordEditParams{
|
||||||
ZoneID: cloudflare.F(zoneID),
|
ZoneID: cloudflare.F(config.CloudflareZoneID),
|
||||||
Record: NewDNS,
|
Record: NewDNS,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue