|
@@ -0,0 +1,185 @@
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "io"
|
|
|
+ "io/ioutil"
|
|
|
+ mu "mfw/util"
|
|
|
+ "net"
|
|
|
+ "net/http"
|
|
|
+ "os/exec"
|
|
|
+ "strings"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+//检测端口是否可用
|
|
|
+func checkPort() (sPorts, fPorts []string) {
|
|
|
+ output, err := exec.Command("netstat", "-tuln").Output()
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("执行netstat命令时出错:", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ lines := strings.Split(string(output), "\n")
|
|
|
+ for _, port := range config.Ports {
|
|
|
+ portOk := false
|
|
|
+ for _, line := range lines {
|
|
|
+ if line == "" {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ fields := strings.Fields(line)
|
|
|
+ if len(fields) >= 4 && strings.Contains(fields[3], fmt.Sprint(port)) { //端口存活
|
|
|
+ portOk = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if portOk {
|
|
|
+ sPorts = append(sPorts, fmt.Sprint(port))
|
|
|
+ } else {
|
|
|
+ fPorts = append(fPorts, fmt.Sprint(port))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+//测速
|
|
|
+func checkSpeed(addr string, updatename bool) (float64, float64) {
|
|
|
+ conn, err := net.Dial("tcp", addr)
|
|
|
+ if err != nil {
|
|
|
+ return 0, 0
|
|
|
+ }
|
|
|
+ defer conn.Close()
|
|
|
+ t1 := time.Now()
|
|
|
+ buf := make([]byte, 1024)
|
|
|
+ for i := 0; i < 50; i++ {
|
|
|
+ io.ReadFull(conn, buf)
|
|
|
+ }
|
|
|
+ dd := time.Since(t1)
|
|
|
+ t1 = time.Now()
|
|
|
+ for i := 0; i < 50; i++ {
|
|
|
+ conn.Write(buf)
|
|
|
+ }
|
|
|
+ for {
|
|
|
+ _, err := conn.Write(buf)
|
|
|
+ if err != nil {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ time.Sleep(10 * time.Millisecond)
|
|
|
+ }
|
|
|
+ ud := time.Since(t1)
|
|
|
+ dp, up := float64(0.05)/dd.Seconds(), float64(0.05)/ud.Seconds()
|
|
|
+ msg := fmt.Sprintf(MSG_TPL, config.VpsName, float64(0.05)/dd.Seconds(), float64(0.05)/ud.Seconds())
|
|
|
+ fmt.Println("网速测试,", msg)
|
|
|
+ if updatename {
|
|
|
+ client.WriteObj("", "", mu.EVENT_UPDATE_MYNAME, mu.SENDTO_TYPE_P2P, []byte(msg))
|
|
|
+ }
|
|
|
+ return dp, up
|
|
|
+}
|
|
|
+
|
|
|
+//切换IP
|
|
|
+func changeIP() {
|
|
|
+ sendMessageBeforChangeIp()
|
|
|
+ defer sendMessageAfterChangeIp()
|
|
|
+ for {
|
|
|
+ fmt.Println("start change ip...")
|
|
|
+ exec.Command("pppoe-stop").Run()
|
|
|
+ exec.Command("pppoe-start").Run()
|
|
|
+ fmt.Println("wait...")
|
|
|
+ time.Sleep(10 * time.Second) //避免换IP后无法获取IP
|
|
|
+ newIp := getMyIp() //获取新IP
|
|
|
+ fmt.Println("newIp:", newIp)
|
|
|
+ if newIp != "" && newIp != myoldip {
|
|
|
+ fmt.Println("公网IP由", myoldip, "换为", newIp)
|
|
|
+ ds, us := checkSpeed(config.CheckSpeedAddr, true) //测速
|
|
|
+ if ds >= config.DownSpeedLimit && us >= config.UploadSpeedLimit { //网速达标
|
|
|
+ fmt.Println("IP测速通过", newIp)
|
|
|
+ myoldip = newIp
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ time.Sleep(5 * time.Second)
|
|
|
+ }
|
|
|
+}
|
|
|
+func sendMessageBeforChangeIp() {
|
|
|
+ fmt.Println("切换IP前发送消息...")
|
|
|
+ bs := []byte{}
|
|
|
+ for _, v := range cache {
|
|
|
+ udpclient.WriteUdp([]byte{}, mu.OP_WILLCHANGEIP, v.Addr) //udp通知本服务器的下载器节点要切换ip,下掉所有服务
|
|
|
+ bs = append(bs, []byte(v.Code)...)
|
|
|
+ }
|
|
|
+ client.WriteObj("", "", mu.SERVICE_DOWNLOAD_DELETE_NODE, mu.SENDTO_TYPE_ALL_RECIVER, bs)
|
|
|
+}
|
|
|
+
|
|
|
+func sendMessageAfterChangeIp() {
|
|
|
+ fmt.Println("切换IP后发送消息...")
|
|
|
+ cacheLock.Lock()
|
|
|
+ for k, v := range cache { //告诉下载器重连
|
|
|
+ udpclient.WriteUdp([]byte{}, mu.OP_NEWCLIENT, v.Addr)
|
|
|
+ delete(cache, k)
|
|
|
+ }
|
|
|
+ cacheLock.Unlock()
|
|
|
+ go func() {
|
|
|
+ for i := 1; i <= 5; i++ {
|
|
|
+ time.Sleep(5 * time.Second)
|
|
|
+ if len(cache) > 0 {
|
|
|
+ bs := []byte{}
|
|
|
+ for k, v := range cache {
|
|
|
+ fmt.Println("本机下载器机器码:", k, v.Code)
|
|
|
+ bs = append(bs, []byte(v.Code)...)
|
|
|
+ }
|
|
|
+ client.WriteObj("", "", mu.SERVICE_DOWNLOAD_APPEND_NODE, mu.SENDTO_TYPE_ALL_RECIVER, bs)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }()
|
|
|
+}
|
|
|
+
|
|
|
+//获取IP
|
|
|
+func getMyIp() (ip string) {
|
|
|
+ for i := 1; i <= 3; i++ {
|
|
|
+ client := &http.Client{
|
|
|
+ Timeout: 5 * time.Second, // 设置超时时间为5秒
|
|
|
+ }
|
|
|
+ resp, err := client.Get("https://api.ipify.org") // 使用ipify.org提供的IP查询API
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("获取公网IP失败:", err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ ipByte, err := ioutil.ReadAll(resp.Body)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("获取公网IP失败:", err)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ resp.Body.Close()
|
|
|
+ ip = string(ipByte)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func checkIpAndPort() (sPorts, fPorts []string) {
|
|
|
+ //检测IP
|
|
|
+ if !changing { //正在切换IP,不做测速检测
|
|
|
+ fmt.Println("测速...")
|
|
|
+ ds, us := checkSpeed(config.CheckSpeedAddr, false) //测速
|
|
|
+ if ds < config.DownSpeedLimit || us < config.UploadSpeedLimit { //网速不达标,切换IP
|
|
|
+ go runChangeIP() //重新切换IP
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fmt.Println("检测端口...")
|
|
|
+ //检测端口
|
|
|
+ sPorts, fPorts = checkPort()
|
|
|
+ if len(fPorts) == len(config.Ports) { //端口都不可用,重启端口
|
|
|
+ go reStartPorts() //本轮检测重启,不可用
|
|
|
+ }
|
|
|
+ time.Sleep(1 * time.Second)
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+//端口重启
|
|
|
+func reStartPorts() {
|
|
|
+ tmpPort := []string{}
|
|
|
+ for _, port := range config.Ports {
|
|
|
+ tmpPort = append(tmpPort, ":"+fmt.Sprint(port))
|
|
|
+ }
|
|
|
+ exec.Command("/bin/sh", "-c", `kill -9 $(pidof "proxy")`).Run() //杀proxy
|
|
|
+ exec.Command("proxy", "socks", "-t", "tcp", "-p", strings.Join(tmpPort, ","), "--forever", "--nolog", "--daemon").Run() //启动proxy
|
|
|
+}
|