123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- package v1
- import (
- "fmt"
- "io/ioutil"
- "math/rand"
- "net"
- "net/http"
- "strings"
- "time"
- "github.com/IceWhaleTech/CasaOS-Common/utils/logger"
- "github.com/IceWhaleTech/CasaOS/common"
- "github.com/IceWhaleTech/CasaOS/pkg/utils/httper"
- "github.com/gin-gonic/gin"
- "github.com/tidwall/gjson"
- "go.uber.org/zap"
- )
- func ZerotierProxy(c *gin.Context) {
- // Read the port number from the file
- w := c.Writer
- r := c.Request
- port, err := ioutil.ReadFile("/var/lib/zerotier-one/zerotier-one.port")
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- // Get the request path and remove "/zt"
- path := strings.TrimPrefix(r.URL.Path, "/v1/zt")
- fmt.Println(path)
- // Build the target URL
- targetURL := fmt.Sprintf("http://localhost:%s%s", strings.TrimSpace(string(port)), path)
- // Create a new request
- req, err := http.NewRequest(r.Method, targetURL, r.Body)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- // Add the X-ZT1-AUTH header
- authToken, err := ioutil.ReadFile("/var/lib/zerotier-one/authtoken.secret")
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- req.Header.Set("X-ZT1-AUTH", strings.TrimSpace(string(authToken)))
- copyHeaders(req.Header, r.Header)
- client := http.Client{}
- resp, err := client.Do(req)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- defer resp.Body.Close()
- copyHeaders(w.Header(), resp.Header)
- respBody, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- // Return the response to the client
- w.WriteHeader(resp.StatusCode)
- w.Write(respBody)
- }
- func copyHeaders(destination, source http.Header) {
- for key, values := range source {
- for _, value := range values {
- destination.Add(key, value)
- }
- }
- }
- func CheckNetwork() {
- logger.Info("start check network")
- respBody, err := httper.ZTGet("/controller/network")
- if err != nil {
- logger.Error("get network error", zap.Error(err))
- return
- }
- networkId := ""
- address := ""
- networkNames := gjson.ParseBytes(respBody).Array()
- routers := ""
- for _, v := range networkNames {
- res, err := httper.ZTGet("/controller/network/" + v.Str)
- if err != nil {
- logger.Error("get network error", zap.Error(err))
- return
- }
- name := gjson.GetBytes(res, "name").Str
- if name == common.RANW_NAME {
- networkId = gjson.GetBytes(res, "id").Str
- routers = gjson.GetBytes(res, "routes.0.target").Str
- break
- }
- }
- ip, s, e, c := getZTIP(routers)
- logger.Info("ip", zap.Any("ip", ip))
- if len(networkId) == 0 {
- if len(address) == 0 {
- address = GetAddress()
- }
- networkId = CreateNet(address, s, e, c)
- }
- res, err := httper.ZTGet("/network")
- if err != nil {
- logger.Error("get network error", zap.Error(err))
- return
- }
- joined := false
- networks := gjson.GetBytes(res, "#.id").Array()
- for _, v := range networks {
- if v.Str == networkId {
- joined = true
- break
- }
- }
- logger.Info("joined", zap.Any("joined", joined))
- if !joined {
- JoinAndUpdateNet(address, networkId, ip)
- }
- }
- func GetAddress() string {
- nodeRes, err := httper.ZTGet("/status")
- if err != nil {
- logger.Error("get status error", zap.Error(err))
- return ""
- }
- return gjson.GetBytes(nodeRes, "address").String()
- }
- func JoinAndUpdateNet(address, networkId, ip string) {
- logger.Info("start join network", zap.Any("ip", ip))
- _, err := httper.ZTPost("/network/"+networkId, "")
- if err != nil {
- logger.Error(" get network error", zap.Error(err))
- return
- }
- if len(address) == 0 {
- address = GetAddress()
- }
- b := `{
- "authorized": true,
- "activeBridge": true,
- "ipAssignments": [
- "` + ip + `"
- ]
- }`
- _, err = httper.ZTPost("/controller/network/"+networkId+"/member/"+address, b)
- if err != nil {
- logger.Error("join network error", zap.Error(err))
- return
- }
- }
- func CreateNet(address, s, e, c string) string {
- body := `{
- "name": "` + common.RANW_NAME + `",
- "private": false,
- "v4AssignMode": {
- "zt": true
- },
- "ipAssignmentPools": [
- {
- "ipRangeStart": "` + s + `",
- "ipRangeEnd": "` + e + `"
- }
- ],
- "routes": [
- {
- "target": "` + c + `"
- }
- ],
- "rules": [
- {
- "etherType": 2048,
- "not": true,
- "or": false,
- "type": "MATCH_ETHERTYPE"
- },
- {
- "etherType": 2054,
- "not": true,
- "or": false,
- "type": "MATCH_ETHERTYPE"
- },
- {
- "etherType": 34525,
- "not": true,
- "or": false,
- "type": "MATCH_ETHERTYPE"
- },
- {
- "type": "ACTION_DROP"
- },
- {
- "type": "ACTION_ACCEPT"
- }
- ],
- "v6AssignMode": {
- "rfc4193": true
- }
- }`
- createRes, err := httper.ZTPost("/controller/network/"+address+"______", body)
- if err != nil {
- logger.Error("post network error", zap.Error(err))
- return ""
- }
- return gjson.GetBytes(createRes, "id").Str
- }
- func GetZTIPs() []gjson.Result {
- res, err := httper.ZTGet("/network")
- if err != nil {
- logger.Error("get network error", zap.Error(err))
- return []gjson.Result{}
- }
- a := gjson.GetBytes(res, "#.routes.0.target")
- return a.Array()
- }
- func getZTIP(routes string) (ip, start, end, cidr string) {
- excluded := GetZTIPs()
- cidrs := []string{
- "10.147.11.0/24",
- "10.147.12.0/24",
- "10.147.13.0/24",
- "10.147.14.0/24",
- "10.147.15.0/24",
- "10.147.16.0/24",
- "10.147.17.0/24",
- "10.147.18.0/24",
- "10.147.19.0/24",
- "10.147.20.0/24",
- "10.240.0.0/16",
- "10.241.0.0/16",
- "10.242.0.0/16",
- "10.243.0.0/16",
- "10.244.0.0/16",
- "10.245.0.0/16",
- "10.246.0.0/16",
- "10.247.0.0/16",
- "10.248.0.0/16",
- "10.249.0.0/16",
- "172.21.0.0/16",
- "172.22.0.0/16",
- "172.23.0.0/16",
- "172.24.0.0/16",
- "172.25.0.0/16",
- "172.26.0.0/16",
- "172.27.0.0/16",
- "172.28.0.0/16",
- "172.29.0.0/16",
- "172.30.0.0/16",
- }
- filteredCidrs := make([]string, 0)
- if len(routes) > 0 {
- filteredCidrs = append(filteredCidrs, routes)
- } else {
- for _, cidr := range cidrs {
- isExcluded := false
- for _, excludedIP := range excluded {
- if cidr == excludedIP.Str {
- isExcluded = true
- break
- }
- }
- if !isExcluded {
- filteredCidrs = append(filteredCidrs, cidr)
- }
- }
- }
- rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
- ip = ""
- if len(filteredCidrs) > 0 {
- randomIndex := rnd.Intn(len(filteredCidrs))
- selectedCIDR := filteredCidrs[randomIndex]
- _, ipNet, err := net.ParseCIDR(selectedCIDR)
- if err != nil {
- logger.Error("ParseCIDR error", zap.Error(err))
- return
- }
- cidr = selectedCIDR
- startIP := ipNet.IP
- endIP := make(net.IP, len(startIP))
- copy(endIP, startIP)
- for i := range startIP {
- endIP[i] |= ^ipNet.Mask[i]
- }
- startIP[3] = 1
- start = startIP.String()
- endIP[3] = 254
- end = endIP.String()
- ipt := ipNet
- ipt.IP[3] = 1
- ip = ipt.IP.String()
- return
- } else {
- logger.Error("No available CIDR found")
- }
- return
- }
|