|
6 | 6 | "math/big" |
7 | 7 | "net" |
8 | 8 | "net/netip" |
| 9 | + "slices" |
| 10 | + "strings" |
9 | 11 | "time" |
10 | 12 |
|
11 | 13 | "github.com/dop251/goja" |
@@ -148,3 +150,119 @@ func AddIsInNet(vm *goja.Runtime) error { |
148 | 150 | return vm.ToValue(r&m == p&m) |
149 | 151 | }) |
150 | 152 | } |
| 153 | + |
| 154 | +func myIPAddressEx() []netip.Addr { |
| 155 | + addrs, err := net.InterfaceAddrs() |
| 156 | + if err != nil { |
| 157 | + return nil |
| 158 | + } |
| 159 | + res := make([]netip.Addr, 0, len(addrs)) |
| 160 | + for _, addr := range addrs { |
| 161 | + ipnet, ok := addr.(*net.IPNet) |
| 162 | + if !ok { |
| 163 | + continue |
| 164 | + } |
| 165 | + na, ok := netip.AddrFromSlice(ipnet.IP) |
| 166 | + if !ok { |
| 167 | + continue |
| 168 | + } |
| 169 | + res = append(res, na.Unmap()) |
| 170 | + } |
| 171 | + return res |
| 172 | +} |
| 173 | + |
| 174 | +func AddMyIPAddressEx(vm *goja.Runtime) error { |
| 175 | + return vm.GlobalObject().Set("myIpAddressEx", func(call goja.FunctionCall) goja.Value { |
| 176 | + res := mapSlice(myIPAddressEx(), func(a netip.Addr) string { return a.String() }) |
| 177 | + return vm.ToValue(strings.Join(res, ";")) |
| 178 | + }) |
| 179 | +} |
| 180 | + |
| 181 | +func netipAddrCmp(a, b netip.Addr) int { |
| 182 | + if a.Is6() == b.Is6() { |
| 183 | + if a.Less(b) { |
| 184 | + return -1 |
| 185 | + } else if b.Less(a) { |
| 186 | + return 1 |
| 187 | + } |
| 188 | + return 0 |
| 189 | + } else { |
| 190 | + if a.Is6() { |
| 191 | + return -1 |
| 192 | + } else { |
| 193 | + return 1 |
| 194 | + } |
| 195 | + } |
| 196 | +} |
| 197 | + |
| 198 | +func AddSortIPAddressList(vm *goja.Runtime) error { |
| 199 | + return vm.GlobalObject().Set("sortIpAddressList", func(call goja.FunctionCall) goja.Value { |
| 200 | + if len(call.Arguments) != 1 { |
| 201 | + panic(vm.NewTypeError("sortIpAddressList expects exactly 1 argument")) |
| 202 | + } |
| 203 | + addrParts := strings.Split(call.Argument(0).String(), ";") |
| 204 | + addrs := make([]netip.Addr, 0, len(addrParts)) |
| 205 | + for _, part := range addrParts { |
| 206 | + addr, err := netip.ParseAddr(part) |
| 207 | + if err != nil { |
| 208 | + return vm.ToValue("") |
| 209 | + } |
| 210 | + addrs = append(addrs, addr) |
| 211 | + } |
| 212 | + slices.SortFunc(addrs, netipAddrCmp) |
| 213 | + res := mapSlice(addrs, func(a netip.Addr) string { return a.String() }) |
| 214 | + return vm.ToValue(strings.Join(res, ";")) |
| 215 | + }) |
| 216 | +} |
| 217 | + |
| 218 | +func dnsResolveEx(host string) []netip.Addr { |
| 219 | + ctx, cl := context.WithTimeout(context.Background(), 5*time.Second) |
| 220 | + defer cl() |
| 221 | + // lookup "ip" network for better cache coherence with other lookups, |
| 222 | + // even though we actually interested only in IPv4 only |
| 223 | + addrs, err := DefaultResolver.LookupNetIP(ctx, "ip", host) |
| 224 | + if err != nil { |
| 225 | + return nil |
| 226 | + } |
| 227 | + for i := range addrs { |
| 228 | + addrs[i] = addrs[i].Unmap() |
| 229 | + } |
| 230 | + return addrs |
| 231 | +} |
| 232 | + |
| 233 | +func AddDNSResolveEx(vm *goja.Runtime) error { |
| 234 | + return vm.GlobalObject().Set("dnsResolveEx", func(call goja.FunctionCall) goja.Value { |
| 235 | + if len(call.Arguments) != 1 { |
| 236 | + panic(vm.NewTypeError("dnsResolveEx expects exactly 1 argument")) |
| 237 | + } |
| 238 | + res := mapSlice(dnsResolveEx(call.Argument(0).String()), func(a netip.Addr) string { return a.String() }) |
| 239 | + return vm.ToValue(strings.Join(res, ";")) |
| 240 | + }) |
| 241 | +} |
| 242 | + |
| 243 | +func AddIsResolvableEx(vm *goja.Runtime) error { |
| 244 | + return vm.GlobalObject().Set("isResolvableEx", func(call goja.FunctionCall) goja.Value { |
| 245 | + if len(call.Arguments) != 1 { |
| 246 | + panic(vm.NewTypeError("isResolvableEx expects exactly 1 argument")) |
| 247 | + } |
| 248 | + res := dnsResolveEx(call.Argument(0).String()) |
| 249 | + return vm.ToValue(len(res) > 0) |
| 250 | + }) |
| 251 | +} |
| 252 | + |
| 253 | +func AddIsInNetEx(vm *goja.Runtime) error { |
| 254 | + return vm.GlobalObject().Set("isInNetEx", func(call goja.FunctionCall) goja.Value { |
| 255 | + if len(call.Arguments) != 2 { |
| 256 | + panic(vm.NewTypeError("isInNet expects exactly 2 arguments")) |
| 257 | + } |
| 258 | + host, err := netip.ParseAddr(call.Argument(0).String()) |
| 259 | + if err != nil { |
| 260 | + return vm.ToValue(false) |
| 261 | + } |
| 262 | + pfx, err := netip.ParsePrefix(call.Argument(1).String()) |
| 263 | + if err != nil { |
| 264 | + return vm.ToValue(false) |
| 265 | + } |
| 266 | + return vm.ToValue(pfx.Contains(host)) |
| 267 | + }) |
| 268 | +} |
0 commit comments