Skip to content

Commit

Permalink
feat: first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ser163 committed Jul 5, 2023
1 parent 4b4f7cd commit 396715b
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.exe
*.yaml
/.idea
31 changes: 31 additions & 0 deletions README.md
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
```
7 changes: 7 additions & 0 deletions config.yaml.bak
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}"
5 changes: 5 additions & 0 deletions go.mod
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
3 changes: 3 additions & 0 deletions go.sum
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=
144 changes: 144 additions & 0 deletions main.go
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
}

0 comments on commit 396715b

Please sign in to comment.