-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
*.exe | ||
*.yaml | ||
/.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# domain_bot | ||
用来go语言编写检测域名过期的程序. | ||
|
||
## 配置文件 | ||
将config.yaml.bak 改为config.yaml | ||
|
||
* `domains` 是一个域名列表. | ||
* `days` 是一个整数,表示域名在过期前多少天进行提示. | ||
* `external` 是一个字符串,表示外部程序的路径. | ||
* `method` 是一个字符串,表示调用外部程序的方式(可以是 `pipe` 或 `args`) | ||
|
||
外部程序推荐使用[ding_pigeon](https://github.com/ser163/ding_pigeon) 给钉钉群发送消息 | ||
* `args` 是一个字符串,表示命令行参数模板(其中 {message} 将被替换为实际的消息内容)。 | ||
|
||
## 编译 | ||
Linux编译 | ||
```shell | ||
go build -ldflags "-s -w" -o domain_bot main.go | ||
``` | ||
|
||
windows下交叉编译 | ||
```shell | ||
set GOOS=linux | ||
set GOARCH=amd64 | ||
go build -ldflags "-s -w" -o domain_bot main.go | ||
``` | ||
|
||
Windows编译exe | ||
```shell | ||
go build -ldflags "-s -w" -o domain_bot.exe main.go | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
domains: | ||
- example.com | ||
- example.net | ||
days: 30 | ||
external: E:\code\go\ding_pigeon\dpingeon.exe | ||
method: args | ||
args: -conf=E:\code\go\ding_pigeon\config.yaml -type=text -content="{message}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module domain_bot | ||
|
||
go 1.20 | ||
|
||
require gopkg.in/yaml.v2 v2.4.0 // indirect |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | ||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"fmt" | ||
"io/ioutil" | ||
"net" | ||
"os/exec" | ||
"regexp" | ||
"strings" | ||
"time" | ||
|
||
"gopkg.in/yaml.v2" | ||
) | ||
|
||
type Config struct { | ||
Domains []string `yaml:"domains"` | ||
Days int `yaml:"days"` | ||
External string `yaml:"external"` | ||
Method string `yaml:"method"` | ||
ArgsTemplate string `yaml:"args"` | ||
} | ||
|
||
func main() { | ||
configFile, err := ioutil.ReadFile("config.yaml") | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
var config Config | ||
err = yaml.Unmarshal(configFile, &config) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
for _, domain := range config.Domains { | ||
expirationDate, err := queryExpirationDate(domain) | ||
if err != nil { | ||
fmt.Printf("查询域名 %s 到期时间失败:%v\n", domain, err) | ||
continue | ||
} | ||
|
||
daysLeft := int(expirationDate.Sub(time.Now()).Hours() / 24) | ||
|
||
fmt.Printf("域名 %s 将在 %s 过期,还剩 %d 天\n", domain, expirationDate.Format("2006-01-02"), daysLeft) | ||
|
||
if daysLeft < config.Days { | ||
message := fmt.Sprintf("域名 %s 将在 %s 过期,还剩 %d 天", domain, expirationDate.Format("2006-01-02"), daysLeft) | ||
err = runExternalProgram(config.External, message, config.Method, config.ArgsTemplate) | ||
if err != nil { | ||
fmt.Printf("运行外部程序 %s 出错: %v\n", config.External, err) | ||
} | ||
} | ||
} | ||
} | ||
|
||
func queryExpirationDate(domain string) (time.Time, error) { | ||
whoisServer, err := getWhoisServer(domain) | ||
if err != nil { | ||
return time.Time{}, err | ||
} | ||
|
||
conn, err := net.Dial("tcp", whoisServer+":43") | ||
if err != nil { | ||
return time.Time{}, err | ||
} | ||
defer conn.Close() | ||
|
||
fmt.Fprintf(conn, domain+"\r\n") | ||
|
||
response, err := ioutil.ReadAll(conn) | ||
if err != nil { | ||
return time.Time{}, err | ||
} | ||
|
||
re := regexp.MustCompile(`(?i)Expir.+?(\d{4}-\d{2}-\d{2})`) | ||
matches := re.FindStringSubmatch(string(response)) | ||
if len(matches) < 2 { | ||
return time.Time{}, errors.New("无法解析域名到期时间") | ||
} | ||
|
||
expirationDate, err := time.Parse("2006-01-02", matches[1]) | ||
if err != nil { | ||
return time.Time{}, err | ||
} | ||
|
||
return expirationDate, nil | ||
} | ||
|
||
func getWhoisServer(domain string) (string, error) { | ||
parts := strings.Split(domain, ".") | ||
tld := parts[len(parts)-1] | ||
|
||
conn, err := net.Dial("tcp", "whois.iana.org:43") | ||
if err != nil { | ||
return "", err | ||
} | ||
defer conn.Close() | ||
|
||
fmt.Fprintf(conn, tld+"\r\n") | ||
|
||
response, err := ioutil.ReadAll(conn) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
re := regexp.MustCompile(`whois:\s*(\S+)`) | ||
matches := re.FindStringSubmatch(string(response)) | ||
if len(matches) < 2 { | ||
return "", errors.New("无法解析 whois 服务器地址") | ||
} | ||
|
||
return matches[1], nil | ||
} | ||
|
||
func runExternalProgram(external string, message string, method string, argsTemplate string) error { | ||
var cmd *exec.Cmd | ||
if method == "args" { | ||
args := strings.Split(argsTemplate, " ") | ||
for i, arg := range args { | ||
args[i] = strings.Replace(arg, "{message}", message, -1) | ||
} | ||
cmd = exec.Command(external, args...) | ||
fmt.Printf("运行命令: %s %v\n", external, args) | ||
} else { | ||
cmd = exec.Command(external) | ||
cmd.Stdin = bytes.NewBufferString(message) | ||
} | ||
var out bytes.Buffer | ||
var stderr bytes.Buffer | ||
cmd.Stdout = &out | ||
cmd.Stderr = &stderr | ||
err := cmd.Run() | ||
if err != nil { | ||
fmt.Printf("运行外部程序 %s 出错: %v\n", external, err) | ||
fmt.Printf("错误信息: %s\n", stderr.String()) | ||
return fmt.Errorf("%v: %s", err, stderr.String()) | ||
} else { | ||
fmt.Printf("运行外部程序 %s 成功\n", external) | ||
fmt.Printf("运行信息: %s\n", out.String()) | ||
} | ||
return nil | ||
} |