Backend: - Add registry_address configuration API (GET/POST) - Add tar image upload with OCI and Docker format support - Add image download with streaming optimization - Fix blob download using c.Send (Fiber v3 SendStream bug) - Add registry_address prefix stripping for all OCI v2 endpoints - Add AGENTS.md for project documentation Frontend: - Add settings store with Snackbar notifications - Add image upload dialog with progress bar - Add download state tracking with multi-stage feedback - Replace alert() with MUI Snackbar messages - Display image names without registry_address prefix 🤖 Generated with [Qoder](https://qoder.com)
230 lines
3.9 KiB
Go
230 lines
3.9 KiB
Go
package tool
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
)
|
|
|
|
var (
|
|
privateIPv4Blocks []*net.IPNet
|
|
privateIPv6Blocks []*net.IPNet
|
|
)
|
|
|
|
func init() {
|
|
// IPv4私有地址段
|
|
for _, cidr := range []string{
|
|
"10.0.0.0/8", // A类私有地址
|
|
"172.16.0.0/12", // B类私有地址
|
|
"192.168.0.0/16", // C类私有地址
|
|
"169.254.0.0/16", // 链路本地地址
|
|
"127.0.0.0/8", // 环回地址
|
|
} {
|
|
_, block, _ := net.ParseCIDR(cidr)
|
|
privateIPv4Blocks = append(privateIPv4Blocks, block)
|
|
}
|
|
|
|
// IPv6私有地址段
|
|
for _, cidr := range []string{
|
|
"fc00::/7", // 唯一本地地址
|
|
"fe80::/10", // 链路本地地址
|
|
"::1/128", // 环回地址
|
|
} {
|
|
_, block, _ := net.ParseCIDR(cidr)
|
|
privateIPv6Blocks = append(privateIPv6Blocks, block)
|
|
}
|
|
}
|
|
|
|
func IsPrivateIP(ipStr string) bool {
|
|
ip := net.ParseIP(ipStr)
|
|
if ip == nil {
|
|
return false
|
|
}
|
|
|
|
// 处理IPv4和IPv4映射的IPv6地址
|
|
if ip4 := ip.To4(); ip4 != nil {
|
|
for _, block := range privateIPv4Blocks {
|
|
if block.Contains(ip4) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// 处理IPv6地址
|
|
for _, block := range privateIPv6Blocks {
|
|
if block.Contains(ip) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func IP2Int(ip net.IP) uint32 {
|
|
if ip == nil {
|
|
return 0
|
|
}
|
|
|
|
ip = ip.To4()
|
|
if ip == nil {
|
|
return 0
|
|
}
|
|
|
|
return binary.BigEndian.Uint32(ip)
|
|
}
|
|
|
|
func Int2IP(ip uint32) net.IP {
|
|
data := make(net.IP, 4)
|
|
binary.BigEndian.PutUint32(data, ip)
|
|
return data
|
|
}
|
|
|
|
func IPStr2Int(ipStr string) *uint32 {
|
|
ip := IP2Int(net.ParseIP(ipStr))
|
|
if ip == 0 {
|
|
return nil
|
|
}
|
|
return &ip
|
|
}
|
|
|
|
func Int2IPStr(ip uint32) string {
|
|
return Int2IP(ip).String()
|
|
}
|
|
|
|
func GetLastIP4(cidr string) (lastIP4 uint32, err error) {
|
|
ip, ipNet, err := net.ParseCIDR(cidr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
firstIP4 := IP2Int(ip.Mask(ipNet.Mask))
|
|
ipNetMaskInt := binary.BigEndian.Uint32(ipNet.Mask)
|
|
lastIP4 = firstIP4 | ^ipNetMaskInt
|
|
return
|
|
}
|
|
|
|
func IsCIDRConflict(cidr1, cidr2 string) (conflict bool, err error) {
|
|
_, ipNet1, err := net.ParseCIDR(cidr1)
|
|
if err != nil {
|
|
return
|
|
}
|
|
_, ipNet2, err := net.ParseCIDR(cidr2)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if ipNet2.Contains(ipNet1.IP) || ipNet1.Contains(ipNet2.IP) {
|
|
conflict = true
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func GetCIDRs(startCIDR, endCIDR string, mask uint8) (cidrs []string, err error) {
|
|
cidrs = append(cidrs, startCIDR)
|
|
|
|
currentCIDR := startCIDR
|
|
for {
|
|
lastIP4, err := GetLastIP4(currentCIDR)
|
|
if err != nil {
|
|
return cidrs, err
|
|
}
|
|
|
|
nextCIDR := Int2IPStr(lastIP4+1) + fmt.Sprintf("/%d", mask)
|
|
cidrs = append(cidrs, nextCIDR)
|
|
|
|
conflict, err := IsCIDRConflict(nextCIDR, endCIDR)
|
|
if err != nil {
|
|
return cidrs, err
|
|
}
|
|
if conflict {
|
|
break
|
|
}
|
|
|
|
currentCIDR = nextCIDR
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func GetLocalIP() (ip string, err error) {
|
|
ifaces, err := net.Interfaces()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for _, iface := range ifaces {
|
|
if iface.Name != "eth0" {
|
|
continue
|
|
}
|
|
|
|
addrs, err := iface.Addrs()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
for _, addr := range addrs {
|
|
switch v := addr.(type) {
|
|
case *net.IPNet:
|
|
ip = v.IP.String()
|
|
if ip == "192.168.88.88" {
|
|
continue
|
|
}
|
|
return ip, err
|
|
case *net.IPAddr:
|
|
ip = v.IP.String()
|
|
if ip == "192.168.88.88" {
|
|
continue
|
|
}
|
|
return ip, err
|
|
}
|
|
}
|
|
}
|
|
|
|
ip = "127.0.0.1"
|
|
|
|
return
|
|
}
|
|
|
|
func LookupIP(host string) (ip string, err error) {
|
|
ips, err := net.LookupIP(host)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for _, i := range ips {
|
|
if ipv4 := i.To4(); ipv4 != nil {
|
|
ip = ipv4.String()
|
|
break
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
func LookupIPv4(host string) (uint32, error) {
|
|
ips, err := net.LookupIP(host)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
for _, i := range ips {
|
|
if ipv4 := i.To4(); ipv4 != nil {
|
|
return binary.BigEndian.Uint32(ipv4), nil
|
|
}
|
|
}
|
|
|
|
return 0, errors.New("host not found " + host)
|
|
}
|
|
|
|
func ResolveIPv4(host string) (uint32, error) {
|
|
addr, err := net.ResolveIPAddr("ip4", host)
|
|
if err == nil && addr != nil {
|
|
addrV4 := binary.BigEndian.Uint32(addr.IP.To4())
|
|
|
|
return addrV4, err
|
|
}
|
|
|
|
return 0, err
|
|
}
|