ipcenter/switch.go

254 lines
5.5 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)
http.HandleFunc("/ippool/switch/allproxies", swi.allProxies)
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()
if err := cmd.Process.Release(); err != nil {
panic(err)
}
cmd = exec.Command("/bin/sh", "-c", "sudo iptables -t nat -F IPSWITCH")
cmd.Run()
if err := cmd.Process.Release(); err != nil {
panic(err)
}
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)
}
if err := cmd.Process.Release(); err != nil {
panic(err)
}
}
server := &http.Server{Addr: addr, Handler: nil}
server.SetKeepAlivesEnabled(false)
server.ListenAndServe()
}
// 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)
}
}
}
}
func (swi *Switch) clearReady(now int64) {
for _, dipg := range swi.Worker.ForMatch {
var delIPList []string
for ip, dhost := range dipg.Ready {
if now >= dhost.ActiveTime+150 {
delIPList = append(delIPList, ip)
}
}
for _, ip := range delIPList {
delete(dipg.Ready, ip)
}
}
}
// checkInReady 签到的IP(vps的vpn节点IP))
func (swi *Switch) checkInReady(ip string, now int64) {
if dipg, ok := swi.Worker.ForMatch[ip]; ok {
if dh, ok := dipg.Waitor[ip]; ok {
if dh.OverTime(now, 20) > 0 {
delete(dipg.Waitor, ip)
} else {
return
}
}
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, req *http.Request) {
defer req.Body.Close()
w.Write([]byte("ok"))
ip := strings.Split(req.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.clearReady(now)
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) {
defer req.Body.Close()
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) {
defer req.Body.Close()
swi.Worker.Mutex.Lock()
defer swi.Worker.Mutex.Unlock()
now := time.Now().Unix()
content := make(map[string]map[string]interface{})
for addr, group := range swi.Worker.ForLoop {
addrmap := make(map[string]interface{})
isappend := int64(0)
var hosts []string
for _, dhost := range group.Group {
if dhost.OverTime(now, 150) == 0 {
isappend++
}
hosts = append(hosts, dhost.Host)
}
if isappend > 1 {
content[addr] = addrmap
addrmap["group"] = hosts
addrmap["city"] = group.City
}
}
jdata, err := json.Marshal(content)
ErrorLog(err)
_, err = w.Write(jdata)
ErrorLog(err)
}
func (swi *Switch) allProxies(w http.ResponseWriter, req *http.Request) {
defer req.Body.Close()
swi.Worker.Mutex.Lock()
defer swi.Worker.Mutex.Unlock()
now := time.Now().Unix()
content := make(map[string]map[string]interface{})
for addr, group := range swi.Worker.ForLoop {
addrmap := make(map[string]interface{})
content[addr] = addrmap
isappend := int64(0)
var hosts []string
for _, dhost := range group.Group {
hosts = append(hosts, dhost.Host)
}
addrmap["group"] = hosts
addrmap["city"] = group.City
}
jdata, err := json.Marshal(content)
ErrorLog(err)
_, err = w.Write(jdata)
ErrorLog(err)
}