feat: option to add own IP api, and better error checks
All checks were successful
golangci-lint / lint (push) Successful in 38s
All checks were successful
golangci-lint / lint (push) Successful in 38s
This commit is contained in:
parent
e937474aa8
commit
e63ab9a14d
4 changed files with 76 additions and 46 deletions
|
@ -18,18 +18,17 @@ this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
utils "git.nadeko.net/fijxu/simple-ddns-client/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Porkbun struct {
|
type Porkbun struct {
|
||||||
|
@ -53,10 +52,10 @@ type Config struct {
|
||||||
UpdateInterval int `json:"updateInterval"`
|
UpdateInterval int `json:"updateInterval"`
|
||||||
Provider string `json:"provider"`
|
Provider string `json:"provider"`
|
||||||
DnsServer string `json:"dnsServer"`
|
DnsServer string `json:"dnsServer"`
|
||||||
|
PublicIpApi string `json:"publicIpApi"`
|
||||||
Porkbun Porkbun `json:"porkbun"`
|
Porkbun Porkbun `json:"porkbun"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var client *http.Client
|
|
||||||
var config *Config
|
var config *Config
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/59889882/specifying-dns-server-for-lookup-in-go
|
// https://stackoverflow.com/questions/59889882/specifying-dns-server-for-lookup-in-go
|
||||||
|
@ -80,22 +79,32 @@ var resolver = &net.Resolver{
|
||||||
|
|
||||||
// TODO: Use UPNP, NAT-PMP or with PCP
|
// TODO: Use UPNP, NAT-PMP or with PCP
|
||||||
func getIpAddress() string {
|
func getIpAddress() string {
|
||||||
req := doGetRequest("https://api.ipify.org")
|
req, err := utils.DoGetRequest(config.PublicIpApi)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("Failed to retrieve public ip address from " + config.PublicIpApi + ": " + err.Error())
|
||||||
|
return ""
|
||||||
|
}
|
||||||
return string(req)
|
return string(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Porkbun) updateIp() {
|
func (p *Porkbun) updateIp() {
|
||||||
dnsIp, err := resolver.LookupHost(context.Background(), p.Domain)
|
dnsIp, err := resolver.LookupHost(context.Background(), p.Domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print("Failed to retrieve IP address for domain " + p.Domain)
|
log.Print("Failed to retrieve IP address for domain " + p.Domain + ": " + err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
if len(dnsIp) > 1 {
|
||||||
log.Print("Current IP of the record " + p.Domain + " is " + dnsIp[0])
|
log.Fatal("The record '" + p.Domain + "' can't contain more than 1 IP address!")
|
||||||
|
}
|
||||||
|
if string(dnsIp[0]) == p.Data.Ip {
|
||||||
|
log.Print("No need to update the IP address of domain '" + p.Domain + "'. IP is already " + p.Data.Ip)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Print("Current IP of the record '" + p.Domain + "' is " + dnsIp[0])
|
||||||
|
|
||||||
p.Data.Ip = getIpAddress()
|
p.Data.Ip = getIpAddress()
|
||||||
|
if p.Data.Ip == "" {
|
||||||
if string(dnsIp[0]) == p.Data.Ip {
|
log.Print("Failed to retrieve current public IP address")
|
||||||
log.Print("No need to update the IP address of domain " + p.Domain + ". IP is already " + p.Data.Ip)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +120,11 @@ func (p *Porkbun) updateIp() {
|
||||||
data, _ := json.Marshal(&p.Data)
|
data, _ := json.Marshal(&p.Data)
|
||||||
queryUrl := domain + "/" + p.Type + "/" + subDomain
|
queryUrl := domain + "/" + p.Type + "/" + subDomain
|
||||||
|
|
||||||
res := doPostRequest("https://api.porkbun.com/api/json/v3/dns/editByNameType/"+queryUrl, data)
|
res, err := utils.DoPostRequest("https://api.porkbun.com/api/json/v3/dns/editByNameType/"+queryUrl, data)
|
||||||
|
if err != nil {
|
||||||
|
log.Print("Failed to update public IP address: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Porkbun returns `{"status":"SUCCESS"}` if the IP address has been
|
// Porkbun returns `{"status":"SUCCESS"}` if the IP address has been
|
||||||
// updated successfully
|
// updated successfully
|
||||||
|
@ -145,40 +158,7 @@ func loadConfig(configPath string) *Config {
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
func doGetRequest(url string) []byte {
|
|
||||||
request, err := http.NewRequest("GET", url, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
res, err := client.Do(request)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
body, err := io.ReadAll(res.Body)
|
|
||||||
|
|
||||||
return body
|
|
||||||
}
|
|
||||||
|
|
||||||
func doPostRequest(url string, data []byte) []byte {
|
|
||||||
request, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
res, err := client.Do(request)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err.Error())
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
body, err := io.ReadAll(res.Body)
|
|
||||||
|
|
||||||
return body
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
client = &http.Client{}
|
|
||||||
var configPath string
|
var configPath string
|
||||||
|
|
||||||
flag.StringVar(&configPath, "c", "/etc/simple-ddns-client/config.json", "config.json path")
|
flag.StringVar(&configPath, "c", "/etc/simple-ddns-client/config.json", "config.json path")
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
"updateInterval": 60,
|
"updateInterval": 60,
|
||||||
"dnsServer": "1.1.1.1:53",
|
"dnsServer": "1.1.1.1:53",
|
||||||
"provider": "porkbun",
|
"provider": "porkbun",
|
||||||
|
"publicIpApi": "https://api.ipify.org",
|
||||||
"porkbun": {
|
"porkbun": {
|
||||||
"apiKey": "pk1_xxx",
|
"apiKey": "pk1_xxx",
|
||||||
"secretApiKey": "sk1_xxx",
|
"secretApiKey": "sk1_xxx",
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -1,3 +1,3 @@
|
||||||
module git.nadeko.net/simple-ddns-client
|
module git.nadeko.net/fijxu/simple-ddns-client
|
||||||
|
|
||||||
go 1.23.4
|
go 1.23.4
|
49
internal/utils.go
Normal file
49
internal/utils.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
var client = &http.Client{}
|
||||||
|
|
||||||
|
func DoGetRequest(url string) ([]byte, error) {
|
||||||
|
request, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := client.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DoPostRequest(url string, data []byte) ([]byte, error) {
|
||||||
|
request, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := client.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return body, nil
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue