Skip to content

Commit

Permalink
enhance some func
Browse files Browse the repository at this point in the history
  • Loading branch information
honwen committed Apr 20, 2017
1 parent bcdc22f commit 810d62b
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 25 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ COMMANDS:
update Update AliYun's DNS DomainRecords Record, Create Record if not exist
auto-update Auto-Update AliYun's DNS DomainRecords Record, Get IP using its getip
GET-IP:
getip Get IP Combine 10 different Web-API
getip Get IP Combine 11 different Web-API
GLOBAL OPTIONS:
--access-key-id value, --id value AliYun's Access Key ID
Expand Down
7 changes: 6 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"math/rand"
"os"

"regexp"
Expand Down Expand Up @@ -93,6 +94,9 @@ func (ak *AccessKey) addRecord(domain, rr, dmType, value string) (err error) {
}

func (ak *AccessKey) doDDNSUpdate(fulldomain, ipaddr string) (err error) {
if getDNS(fulldomain) == ipaddr {
return // Skip
}
rr := regexp.MustCompile(`\.[^\.]*`).ReplaceAllString(fulldomain, "")
domain := regexp.MustCompile(`^[^\.]*\.`).ReplaceAllString(fulldomain, "")
// fmt.Println(rr, domain)
Expand Down Expand Up @@ -240,7 +244,7 @@ func main() {
{
Name: "getip",
Category: "GET-IP",
Usage: " Get IP Combine 10 different Web-API",
Usage: fmt.Sprintf(" Get IP Combine %d different Web-API", len(ipAPI)),
Action: func(c *cli.Context) error {
// fmt.Println(c.Command.Name, "task: ", c.Command.Usage)
fmt.Println(getIP())
Expand Down Expand Up @@ -271,5 +275,6 @@ func appInit(c *cli.Context) error {
cli.ShowAppHelp(c)
return errors.New("access-key is empty")
}
rand.Seed(time.Now().UnixNano())
return nil
}
105 changes: 82 additions & 23 deletions utils.go
Original file line number Diff line number Diff line change
@@ -1,55 +1,60 @@
package main

import (
"fmt"
"io/ioutil"
"math/rand"
"net/http"
"regexp"
"sync"
"strings"
"time"

"github.com/miekg/dns"
)

const defaultTimeout = 333 * time.Millisecond
const minTimeout = 333 * time.Millisecond
const regxIP = `(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)`

var ipAPI = []string{
"http://ip.cn", "http://ipinfo.io", "http://ifconfig.co", "http://myip.ipip.net",
"http://cnc.synology.cn:81", "http://jpc.synology.com:81", "http://usc.synology.com:81",
"http://ip.6655.com/ip.aspx", "http://pv.sohu.com/cityjson?ie=utf-8", "http://whois.pconline.com.cn/ipJson.jsp",
"http://ddns.oray.com/checkip",
}

func getIP() (ip string) {
var (
wg sync.WaitGroup
lc sync.Mutex
ipMap = make(map[string]int, len(ipAPI))
length = len(ipAPI)
ipMap = make(map[string]int, length)
cchan = make(chan string, length)
regx = regexp.MustCompile(regxIP)
maxCount = -1
)
for _, url := range ipAPI {
wg.Add(1)
go func(url string) {
ip := regexp.MustCompile(regxIP).FindString(wGet(url, defaultTimeout))
// log.Println(ip, url)
if len(ip) > 0 {
lc.Lock()
ipMap[ip]++
lc.Unlock()
}
wg.Done()
cchan <- regx.FindString(wGet(url, minTimeout))
}(url)
}
wg.Wait()
max := 0
for i := 0; i < length; i++ {
v := <-cchan
if 0 == len(v) {
continue
}
if ipMap[v] >= length/2 {
return v
}
ipMap[v]++
}
for k, v := range ipMap {
if v > len(ipAPI)/2 {
return k
} else if v > max {
max = v
if v > maxCount {
maxCount = v
ip = k
}
}

if len(ip) == 0 {
// Use First ipAPI as failsafe
ip = regexp.MustCompile(regxIP).FindString(wGet(ipAPI[0], 20*defaultTimeout))
// Use First ipAPI as failsafe
if 0 == len(ip) {
ip = regexp.MustCompile(regxIP).FindString(wGet(ipAPI[0], 20*minTimeout))
}
return
}
Expand All @@ -71,3 +76,57 @@ func wGet(url string, timeout time.Duration) (str string) {
str = string(body)
return
}

func getDNS(domain string) (ip string) {
var (
maxServerCount = 5
dnsMap = make(map[string]int, maxServerCount)
cchan = make(chan string, maxServerCount)
maxCount = -1
udpClient = &dns.Client{Net: "udp", Timeout: time.Second}
)

for i := 0; i < maxServerCount; i++ {
go func(dns string) {
cchan <- getFisrtARecord(udpClient, dns, domain)
}(fmt.Sprintf("dns%d.hichina.com:53", rand.Intn(30)+1))
}

for i := 0; i < maxServerCount; i++ {
v := <-cchan
if len(v) == 0 {
continue
}
if dnsMap[v] >= maxServerCount/2 {
return v
}
dnsMap[v]++
}

for k, v := range dnsMap {
if v > maxCount {
maxCount = v
ip = k
}
}
return
}

func getFisrtARecord(client *dns.Client, dnsServer, targetDomain string) (ip string) {
if !strings.HasSuffix(targetDomain, ".") {
targetDomain += "."
}
msg := new(dns.Msg)
msg.SetQuestion(targetDomain, dns.TypeA)
r, _, err := client.Exchange(msg, dnsServer)
if err != nil && (r == nil || r.Rcode != dns.RcodeSuccess) {
return
}
for _, rr := range r.Answer {
if a, ok := rr.(*dns.A); ok {
ip = a.A.String()
break
}
}
return
}

0 comments on commit 810d62b

Please sign in to comment.