diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6523a00 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/Run/ +/.idea/ \ No newline at end of file diff --git a/README.md b/README.md index 4f48184..0bd99d3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,19 @@ # DockerST -Docker官方源加速程序 + +本项目旨在于直接加速Docker官方源,提高Docker镜像下载速度 +Docker官方使用的是CloudFlare的CDN 优选CloudFlare IP后即可实现高速下载 进行原生加速 + +## 安装本程序 + +```bash + +``` + +## 使用代理优选加速(推荐) + +```bash +https://docker.sxh.workers.dev/ +``` + +## 直接加速 + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6d60f8e --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module DockerST + +go 1.22 diff --git a/main.go b/main.go new file mode 100644 index 0000000..6eceeca --- /dev/null +++ b/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "DockerST/task" + "flag" + "fmt" +) + +var ( + VersionPrint bool + Version string +) + +func init() { + // checkUpdate() + // 定义一个字符串类型的命令行标志 + flag.IntVar(&task.TcpPort, "p", 443, "TCP端口") + flag.IntVar(&task.PingTimes, "t", 4, "Ping次数") + flag.IntVar(&task.Routines, "r", 200, "并发数") + flag.BoolVar(&VersionPrint, "v", false, "输出版本") + flag.BoolVar(&task.IsOff, "om", false, "是否为离线模式") + flag.Parse() + if VersionPrint { + fmt.Println("Version:", Version) + } +} + +func main() { + if VersionPrint { + return + } + // 输出版本 + fmt.Printf("# DockerST %s \n", Version) + _ = task.CreateData().Run() +} + +func WriteHost(domain string, ip string) { + +} + +func checkUpdate() { +} diff --git a/task/ip.go b/task/ip.go new file mode 100644 index 0000000..f5b0667 --- /dev/null +++ b/task/ip.go @@ -0,0 +1,136 @@ +package task + +import ( + "encoding/json" + "fmt" + "io" + "io/ioutil" + "math/rand" + "net" + "net/http" + "sync" + "time" +) + +var ( + Ipv4Cidr = []string{ + "173.245.48.0/20", + "103.21.244.0/22", + "103.22.200.0/22", + "103.31.4.0/22", + "141.101.64.0/18", + "108.162.192.0/18", + "190.93.240.0/20", + "188.114.96.0/20", + "197.234.240.0/22", + "198.41.128.0/17", + "162.158.0.0/15", + "104.16.0.0/13", + "104.24.0.0/14", + "172.64.0.0/13", + "131.0.72.0/22", + } + IPCidrApi = "https://api.cloudflare.com/client/v4/ips" + IsOff = false +) + +type IPRangeList struct { + Ips []*net.IPAddr + unusedIpCount int + wg sync.WaitGroup +} + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// CreateData 从IP列表中选择一定数量的IP返回 +func CreateData() *IPRangeList { + ips := loadIPRanges(GetIPv4List()) + return &IPRangeList{ + Ips: ips, + unusedIpCount: 0, + } +} + +// loadIPRanges 从CIDR列表中加载IP地址 +func loadIPRanges(ciders []string) []*net.IPAddr { + var ipAddresses []*net.IPAddr + for _, cidr := range ciders { + _, ipnet, err := net.ParseCIDR(cidr) + if err != nil { + fmt.Printf("解析CIDR %s 时出错: %v\n", cidr, err) + continue + } + // 计算给定IPNet的范围 + ones, _ := ipnet.Mask.Size() + if ones > 24 { + fmt.Printf("CIDR %s 小于 /24\n", cidr) + continue + } + numSubnets := 1 << (24 - ones) + for i := 0; i < numSubnets; i++ { + ip := generateRandomIP(ipnet, i) + ipAddresses = append(ipAddresses, ip) + } + } + return ipAddresses +} + +// generateRandomIP 在给定IPNet范围内生成随机IP地址 +func generateRandomIP(ipnet *net.IPNet, subnetIndex int) *net.IPAddr { + ip := ipnet.IP.To4() + if ip == nil { + return nil + } + // 设置第三个字节为子网索引 + ip[2] = ip[2] + byte(subnetIndex) + // 为最后一个字节生成随机值 + ip[3] = byte(rand.Intn(256)) + return &net.IPAddr{IP: ip} +} + +// GetIPv4List 获取IPv4 CIDR列表 +func GetIPv4List() []string { + // 离线变量 + if IsOff { + return Ipv4Cidr + } + // 获取在线IPv4 CIDR列表 + resp, err := http.Get(IPCidrApi) + if err != nil { + fmt.Println("获取在线列表失败,正在使用内置列表") + return Ipv4Cidr + } + defer func(Body io.ReadCloser) { + _ = Body.Close() + }(resp.Body) + + // 读取响应主体 + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + fmt.Println("获取在线列表失败,正在使用内置列表") + return Ipv4Cidr + } + + // 解析JSON数据 + var data struct { + Result struct { + IPv4CIDRs []string `json:"ipv4_cidrs"` + } `json:"result"` + Success bool `json:"success"` + } + + if err := json.Unmarshal(body, &data); err != nil || !data.Success { + fmt.Println("获取在线列表失败,正在使用内置列表") + return Ipv4Cidr + } + + fmt.Println("获取在线列表成功,正在使用在线列表") + return data.Result.IPv4CIDRs +} + +// IsIpv4 检查IP地址是否为IPv4 +func IsIpv4(ip string) bool { + return net.ParseIP(ip) != nil +} diff --git a/task/tcpping.go b/task/tcpping.go new file mode 100644 index 0000000..6be0046 --- /dev/null +++ b/task/tcpping.go @@ -0,0 +1,52 @@ +package task + +import ( + "fmt" + "net" + "time" +) + +var ( + TcpPort = 443 + PingTimes = 4 + Routines = 200 + TcpConnectTimeOut = time.Second * 1 +) + +func (p *IPRangeList) Run() *IPRangeList { + ch := make(chan struct{}, Routines) + for _, ip := range p.Ips { + p.wg.Add(1) + ch <- struct{}{} // 控制最大并发数 + go func(ip *net.IPAddr) { + defer p.wg.Done() + defer func() { <-ch }() // 释放并发控制 + success, duration := TCPing(ip) + if success { + p.unusedIpCount++ + } else { + // 删除 + } + fmt.Printf("IP: %s, Success: %t, Duration: %v\n", ip.String(), success, duration) + }(ip) + } + // 多线程执行 + return p +} + +func TCPing(ip *net.IPAddr) (bool, time.Duration) { + startTime := time.Now() + var fullAddress string + if IsIpv4(ip.String()) { + fullAddress = fmt.Sprintf("%s:%d", ip.String(), TcpPort) + } else { + fullAddress = fmt.Sprintf("[%s]:%d", ip.String(), TcpPort) + } + conn, err := net.DialTimeout("tcp", fullAddress, TcpConnectTimeOut) + if err != nil { + return false, 0 + } + defer conn.Close() + duration := time.Since(startTime) + return true, duration +}