176 lines
3.8 KiB
Go
176 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
"net/http"
|
|
"os/exec"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Switch 轮换IP相关类
|
|
type Switch struct {
|
|
// config map[string]interface{}
|
|
// configMutex sync.Mutex
|
|
ipregion *regexp.Regexp
|
|
lastShow int64
|
|
lastSwitch int64
|
|
|
|
Worker *DIPWorker
|
|
AO *AlertOver
|
|
}
|
|
|
|
// SetAddrForward 设置当前ip 转发的节点
|
|
func SetAddrForward(num, addr, ip string) {
|
|
port := strings.Split(addr, ":")[1]
|
|
cmd := exec.Command("/bin/sh", "-c", "sudo iptables -t nat -R IPSWITCH "+num+" -p tcp --dport "+port+" -j DNAT --to "+ip+":8885")
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// NewSwitch 初始化默认
|
|
func NewSwitch() *Switch {
|
|
swi := Switch{}
|
|
swi.Worker = NewDipWorker("actives.yaml")
|
|
swi.AO = &AlertOver{}
|
|
swi.AO.SetDefaultSetting()
|
|
|
|
log.Println(swi.Worker.ShowGroupInfo())
|
|
|
|
http.HandleFunc("/ippool/switch/imactive", swi.imActive)
|
|
http.HandleFunc("/ippool/switch/update", swi.updateActives)
|
|
http.HandleFunc("/ippool/switch/actives", swi.switchActives)
|
|
|
|
return &swi
|
|
}
|
|
|
|
// Run addr 监听的地址addr
|
|
// ipregion 匹配adsl的规则, 作为ping服务器并且控制网络转发的调度
|
|
func (swi *Switch) Run(addr string, ipregion string) {
|
|
swi.ipregion = regexp.MustCompile(ipregion)
|
|
|
|
cmd := exec.Command("/bin/sh", "-c", "sudo iptables -t nat -N IPSWITCH")
|
|
cmd.Run()
|
|
|
|
cmd = exec.Command("/bin/sh", "-c", "sudo iptables -t nat -F IPSWITCH")
|
|
cmd.Run()
|
|
|
|
for range swi.Worker.ForLoop {
|
|
cmd := exec.Command("/bin/sh", "-c", "sudo iptables -t nat -A IPSWITCH -p icmp -s 1.1.1.1 -j DNAT --to 1.1.1.1:8885")
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
http.ListenAndServe(addr, nil)
|
|
|
|
}
|
|
|
|
// timeToSwitch 计算是否到切换时间
|
|
func (swi *Switch) timeToSwitch(now int64) {
|
|
for addr, group := range swi.Worker.ForLoop {
|
|
if group.Current == nil {
|
|
group.Choose(addr)
|
|
} else {
|
|
if now >= group.Current.ActiveTime+swi.Worker.Restart {
|
|
// log.Println(now, group.Current.ActiveTime, swi.Worker.Restart)
|
|
group.Choose(addr)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// checkInReady 签到的IP(vps的vpn节点IP))
|
|
func (swi *Switch) checkInReady(ip string, now int64) {
|
|
|
|
if dipg, ok := swi.Worker.ForMatch[ip]; ok {
|
|
|
|
dipg.Group[ip].ActiveTime = now
|
|
|
|
if dipg.Current == nil {
|
|
dhost := NewDHost(ip)
|
|
dhost.ActiveTime = now
|
|
dipg.Ready[ip] = dhost
|
|
} else {
|
|
|
|
if dipg.Current.Host != ip {
|
|
if v, ok := dipg.Ready[ip]; ok {
|
|
v.ActiveTime = now
|
|
} else {
|
|
dhost := NewDHost(ip)
|
|
dhost.ActiveTime = now
|
|
dipg.Ready[ip] = dhost
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// imActive 子节点访问 证明自己是活跃
|
|
func (swi *Switch) imActive(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.Write([]byte("ok"))
|
|
ip := strings.Split(r.RemoteAddr, ":")[0]
|
|
// log.Println(ip) // 后续可以把这些节点, 自动活跃与更新
|
|
|
|
swi.Worker.Mutex.Lock()
|
|
defer swi.Worker.Mutex.Unlock()
|
|
|
|
now := time.Now().Unix()
|
|
|
|
// 60秒show一次日志
|
|
if now >= swi.lastShow+60 {
|
|
swi.lastShow = now
|
|
log.Println("\n" + swi.Worker.ShowGroupInfo())
|
|
}
|
|
|
|
// 5秒一次检测
|
|
if now >= swi.lastSwitch+5 {
|
|
swi.lastSwitch = now
|
|
swi.timeToSwitch(now)
|
|
}
|
|
|
|
swi.checkInReady(ip, now)
|
|
}
|
|
|
|
// updateActives 更新最新配置
|
|
func (swi *Switch) updateActives(w http.ResponseWriter, req *http.Request) {
|
|
|
|
swi.Worker.Mutex.Lock()
|
|
defer swi.Worker.Mutex.Unlock()
|
|
|
|
swi.Worker = NewDipWorker("actives.yaml")
|
|
w.Write([]byte("update success!"))
|
|
}
|
|
|
|
func (swi *Switch) switchActives(w http.ResponseWriter, req *http.Request) {
|
|
|
|
swi.Worker.Mutex.Lock()
|
|
defer swi.Worker.Mutex.Unlock()
|
|
|
|
now := time.Now().Unix()
|
|
|
|
var content []string
|
|
for addr, group := range swi.Worker.ForLoop {
|
|
|
|
isappend := int64(1)
|
|
for _, dhost := range group.Group {
|
|
isappend *= dhost.OverTime(now)
|
|
}
|
|
if isappend == 0 {
|
|
content = append(content, addr)
|
|
}
|
|
}
|
|
jdata, err := json.Marshal(content)
|
|
ErrorLog(err)
|
|
_, err = w.Write(jdata)
|
|
ErrorLog(err)
|
|
|
|
}
|