Refactor: metadata use netip.Addr
This commit is contained in:
parent
6c4791480e
commit
7ca1a03d73
45 changed files with 374 additions and 346 deletions
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -64,9 +65,9 @@ func (p *Proxy) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
|
|||
|
||||
// DelayHistory implements C.Proxy
|
||||
func (p *Proxy) DelayHistory() []C.DelayHistory {
|
||||
queue := p.history.Copy()
|
||||
queueM := p.history.Copy()
|
||||
histories := []C.DelayHistory{}
|
||||
for _, item := range queue {
|
||||
for _, item := range queueM {
|
||||
histories = append(histories, item)
|
||||
}
|
||||
return histories
|
||||
|
@ -95,7 +96,7 @@ func (p *Proxy) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
|
||||
mapping := map[string]any{}
|
||||
json.Unmarshal(inner, &mapping)
|
||||
_ = json.Unmarshal(inner, &mapping)
|
||||
mapping["history"] = p.DelayHistory()
|
||||
mapping["name"] = p.Name()
|
||||
mapping["udp"] = p.SupportUDP()
|
||||
|
@ -129,7 +130,9 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer instance.Close()
|
||||
defer func() {
|
||||
_ = instance.Close()
|
||||
}()
|
||||
|
||||
req, err := http.NewRequest(http.MethodHead, url, nil)
|
||||
if err != nil {
|
||||
|
@ -138,7 +141,7 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) {
|
|||
req = req.WithContext(ctx)
|
||||
|
||||
transport := &http.Transport{
|
||||
Dial: func(string, string) (net.Conn, error) {
|
||||
DialContext: func(context.Context, string, string) (net.Conn, error) {
|
||||
return instance, nil
|
||||
},
|
||||
// from http.DefaultTransport
|
||||
|
@ -167,8 +170,7 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
resp.Body.Close()
|
||||
_ = resp.Body.Close()
|
||||
t = uint16(time.Since(start) / time.Millisecond)
|
||||
return
|
||||
}
|
||||
|
@ -199,7 +201,7 @@ func urlToMetadata(rawURL string) (addr C.Metadata, err error) {
|
|||
addr = C.Metadata{
|
||||
AddrType: C.AtypDomainName,
|
||||
Host: u.Hostname(),
|
||||
DstIP: nil,
|
||||
DstIP: netip.Addr{},
|
||||
DstPort: port,
|
||||
}
|
||||
return
|
||||
|
|
|
@ -37,7 +37,7 @@ func NewInner(conn net.Conn, dst string, host string) *context.ConnContext {
|
|||
metadata.DstPort = port
|
||||
if host == "" {
|
||||
metadata.DstIP = ip
|
||||
if ip.To4() == nil {
|
||||
if ip.Is4() {
|
||||
metadata.AddrType = C.AtypIPv6
|
||||
} else {
|
||||
metadata.AddrType = C.AtypIPv4
|
||||
|
|
|
@ -3,9 +3,11 @@ package inbound
|
|||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/transport/socks5"
|
||||
)
|
||||
|
@ -21,12 +23,10 @@ func parseSocksAddr(target socks5.Addr) *C.Metadata {
|
|||
metadata.Host = strings.TrimRight(string(target[2:2+target[1]]), ".")
|
||||
metadata.DstPort = strconv.Itoa((int(target[2+target[1]]) << 8) | int(target[2+target[1]+1]))
|
||||
case socks5.AtypIPv4:
|
||||
ip := net.IP(target[1 : 1+net.IPv4len])
|
||||
metadata.DstIP = ip
|
||||
metadata.DstIP = nnip.IpToAddr(net.IP(target[1 : 1+net.IPv4len]))
|
||||
metadata.DstPort = strconv.Itoa((int(target[1+net.IPv4len]) << 8) | int(target[1+net.IPv4len+1]))
|
||||
case socks5.AtypIPv6:
|
||||
ip := net.IP(target[1 : 1+net.IPv6len])
|
||||
metadata.DstIP = ip
|
||||
metadata.DstIP = nnip.IpToAddr(net.IP(target[1 : 1+net.IPv6len]))
|
||||
metadata.DstPort = strconv.Itoa((int(target[1+net.IPv6len]) << 8) | int(target[1+net.IPv6len+1]))
|
||||
}
|
||||
|
||||
|
@ -47,14 +47,14 @@ func parseHTTPAddr(request *http.Request) *C.Metadata {
|
|||
NetWork: C.TCP,
|
||||
AddrType: C.AtypDomainName,
|
||||
Host: host,
|
||||
DstIP: nil,
|
||||
DstIP: netip.Addr{},
|
||||
DstPort: port,
|
||||
}
|
||||
|
||||
ip := net.ParseIP(host)
|
||||
if ip != nil {
|
||||
ip, err := netip.ParseAddr(host)
|
||||
if err == nil {
|
||||
switch {
|
||||
case ip.To4() == nil:
|
||||
case ip.Is6():
|
||||
metadata.AddrType = C.AtypIPv6
|
||||
default:
|
||||
metadata.AddrType = C.AtypIPv4
|
||||
|
@ -65,12 +65,12 @@ func parseHTTPAddr(request *http.Request) *C.Metadata {
|
|||
return metadata
|
||||
}
|
||||
|
||||
func parseAddr(addr string) (net.IP, string, error) {
|
||||
func parseAddr(addr string) (netip.Addr, string, error) {
|
||||
host, port, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
return netip.Addr{}, "", err
|
||||
}
|
||||
|
||||
ip := net.ParseIP(host)
|
||||
return ip, port, nil
|
||||
ip, err := netip.ParseAddr(host)
|
||||
return ip, port, err
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ var (
|
|||
|
||||
func tcpKeepAlive(c net.Conn) {
|
||||
if tcp, ok := c.(*net.TCPConn); ok {
|
||||
tcp.SetKeepAlive(true)
|
||||
tcp.SetKeepAlivePeriod(30 * time.Second)
|
||||
_ = tcp.SetKeepAlive(true)
|
||||
_ = tcp.SetKeepAlivePeriod(30 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,14 +48,14 @@ func serializesSocksAddr(metadata *C.Metadata) []byte {
|
|||
port := []byte{uint8(p >> 8), uint8(p & 0xff)}
|
||||
switch metadata.AddrType {
|
||||
case socks5.AtypDomainName:
|
||||
len := uint8(len(metadata.Host))
|
||||
lenM := uint8(len(metadata.Host))
|
||||
host := []byte(metadata.Host)
|
||||
buf = [][]byte{{aType, len}, host, port}
|
||||
buf = [][]byte{{aType, lenM}, host, port}
|
||||
case socks5.AtypIPv4:
|
||||
host := metadata.DstIP.To4()
|
||||
host := metadata.DstIP.AsSlice()
|
||||
buf = [][]byte{{aType}, host, port}
|
||||
case socks5.AtypIPv6:
|
||||
host := metadata.DstIP.To16()
|
||||
host := metadata.DstIP.AsSlice()
|
||||
buf = [][]byte{{aType}, host, port}
|
||||
}
|
||||
return bytes.Join(buf, nil)
|
||||
|
@ -76,6 +76,6 @@ func resolveUDPAddr(network, address string) (*net.UDPAddr, error) {
|
|||
|
||||
func safeConnClose(c net.Conn, err error) {
|
||||
if err != nil {
|
||||
c.Close()
|
||||
_ = c.Close()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -259,11 +259,11 @@ func parseVlessAddr(metadata *C.Metadata) *vless.DstAddr {
|
|||
case C.AtypIPv4:
|
||||
addrType = byte(vless.AtypIPv4)
|
||||
addr = make([]byte, net.IPv4len)
|
||||
copy(addr[:], metadata.DstIP.To4())
|
||||
copy(addr[:], metadata.DstIP.AsSlice())
|
||||
case C.AtypIPv6:
|
||||
addrType = byte(vless.AtypIPv6)
|
||||
addr = make([]byte, net.IPv6len)
|
||||
copy(addr[:], metadata.DstIP.To16())
|
||||
copy(addr[:], metadata.DstIP.AsSlice())
|
||||
case C.AtypDomainName:
|
||||
addrType = byte(vless.AtypDomainName)
|
||||
addr = make([]byte, len(metadata.Host)+1)
|
||||
|
|
|
@ -342,11 +342,11 @@ func parseVmessAddr(metadata *C.Metadata) *vmess.DstAddr {
|
|||
case C.AtypIPv4:
|
||||
addrType = byte(vmess.AtypIPv4)
|
||||
addr = make([]byte, net.IPv4len)
|
||||
copy(addr[:], metadata.DstIP.To4())
|
||||
copy(addr[:], metadata.DstIP.AsSlice())
|
||||
case C.AtypIPv6:
|
||||
addrType = byte(vmess.AtypIPv6)
|
||||
addr = make([]byte, net.IPv6len)
|
||||
copy(addr[:], metadata.DstIP.To16())
|
||||
copy(addr[:], metadata.DstIP.AsSlice())
|
||||
case C.AtypDomainName:
|
||||
addrType = byte(vmess.AtypDomainName)
|
||||
addr = make([]byte, len(metadata.Host)+1)
|
||||
|
|
|
@ -51,7 +51,7 @@ func getKey(metadata *C.Metadata) string {
|
|||
}
|
||||
}
|
||||
|
||||
if metadata.DstIP == nil {
|
||||
if !metadata.DstIP.IsValid() {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package outboundgroup
|
|||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
|
@ -15,20 +16,20 @@ func addrToMetadata(rawAddress string) (addr *C.Metadata, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
ip := net.ParseIP(host)
|
||||
if ip == nil {
|
||||
ip, err := netip.ParseAddr(host)
|
||||
if err != nil {
|
||||
addr = &C.Metadata{
|
||||
AddrType: C.AtypDomainName,
|
||||
Host: host,
|
||||
DstIP: nil,
|
||||
DstIP: netip.Addr{},
|
||||
DstPort: port,
|
||||
}
|
||||
return
|
||||
} else if ip4 := ip.To4(); ip4 != nil {
|
||||
} else if ip.Is4() {
|
||||
addr = &C.Metadata{
|
||||
AddrType: C.AtypIPv4,
|
||||
Host: "",
|
||||
DstIP: ip4,
|
||||
DstIP: ip,
|
||||
DstPort: port,
|
||||
}
|
||||
return
|
||||
|
@ -45,7 +46,7 @@ func addrToMetadata(rawAddress string) (addr *C.Metadata, err error) {
|
|||
|
||||
func tcpKeepAlive(c net.Conn) {
|
||||
if tcp, ok := c.(*net.TCPConn); ok {
|
||||
tcp.SetKeepAlive(true)
|
||||
tcp.SetKeepAlivePeriod(30 * time.Second)
|
||||
_ = tcp.SetKeepAlive(true)
|
||||
_ = tcp.SetKeepAlivePeriod(30 * time.Second)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
"github.com/Dreamacro/clash/component/iface"
|
||||
|
||||
"github.com/insomniacslk/dhcp/dhcpv4"
|
||||
|
@ -15,14 +17,16 @@ var (
|
|||
ErrNotFound = errors.New("DNS option not found")
|
||||
)
|
||||
|
||||
func ResolveDNSFromDHCP(context context.Context, ifaceName string) ([]net.IP, error) {
|
||||
func ResolveDNSFromDHCP(context context.Context, ifaceName string) ([]netip.Addr, error) {
|
||||
conn, err := ListenDHCPClient(context, ifaceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
|
||||
result := make(chan []net.IP, 1)
|
||||
result := make(chan []netip.Addr, 1)
|
||||
|
||||
ifaceObj, err := iface.ResolveInterface(ifaceName)
|
||||
if err != nil {
|
||||
|
@ -52,7 +56,7 @@ func ResolveDNSFromDHCP(context context.Context, ifaceName string) ([]net.IP, er
|
|||
}
|
||||
}
|
||||
|
||||
func receiveOffer(conn net.PacketConn, id dhcpv4.TransactionID, result chan<- []net.IP) {
|
||||
func receiveOffer(conn net.PacketConn, id dhcpv4.TransactionID, result chan<- []netip.Addr) {
|
||||
defer close(result)
|
||||
|
||||
buf := make([]byte, dhcpv4.MaxMessageSize)
|
||||
|
@ -77,11 +81,17 @@ func receiveOffer(conn net.PacketConn, id dhcpv4.TransactionID, result chan<- []
|
|||
}
|
||||
|
||||
dns := pkt.DNS()
|
||||
if len(dns) == 0 {
|
||||
l := len(dns)
|
||||
if l == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
result <- dns
|
||||
dnsAddr := make([]netip.Addr, l)
|
||||
for i := 0; i < l; i++ {
|
||||
dnsAddr[i] = nnip.IpToAddr(dns[i])
|
||||
}
|
||||
|
||||
result <- dnsAddr
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package dialer
|
|||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"syscall"
|
||||
|
||||
"github.com/Dreamacro/clash/component/iface"
|
||||
|
@ -19,13 +20,10 @@ func bindControl(ifaceIdx int, chain controlFn) controlFn {
|
|||
}
|
||||
}()
|
||||
|
||||
ipStr, _, err := net.SplitHostPort(address)
|
||||
if err == nil {
|
||||
ip := net.ParseIP(ipStr)
|
||||
if ip != nil && !ip.IsGlobalUnicast() {
|
||||
addrPort, err := netip.ParseAddrPort(address)
|
||||
if err == nil && !addrPort.Addr().IsGlobalUnicast() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var innerErr error
|
||||
err = c.Control(func(fd uintptr) {
|
||||
|
@ -45,7 +43,7 @@ func bindControl(ifaceIdx int, chain controlFn) controlFn {
|
|||
}
|
||||
}
|
||||
|
||||
func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ net.IP) error {
|
||||
func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.Addr) error {
|
||||
ifaceObj, err := iface.ResolveInterface(ifaceName)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -2,6 +2,7 @@ package dialer
|
|||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
@ -17,13 +18,10 @@ func bindControl(ifaceName string, chain controlFn) controlFn {
|
|||
}
|
||||
}()
|
||||
|
||||
ipStr, _, err := net.SplitHostPort(address)
|
||||
if err == nil {
|
||||
ip := net.ParseIP(ipStr)
|
||||
if ip != nil && !ip.IsGlobalUnicast() {
|
||||
addrPort, err := netip.ParseAddrPort(address)
|
||||
if err == nil && !addrPort.Addr().IsGlobalUnicast() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var innerErr error
|
||||
err = c.Control(func(fd uintptr) {
|
||||
|
@ -38,7 +36,7 @@ func bindControl(ifaceName string, chain controlFn) controlFn {
|
|||
}
|
||||
}
|
||||
|
||||
func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ net.IP) error {
|
||||
func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ netip.Addr) error {
|
||||
dialer.Control = bindControl(ifaceName, dialer.Control)
|
||||
|
||||
return nil
|
||||
|
|
|
@ -4,27 +4,28 @@ package dialer
|
|||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Dreamacro/clash/component/iface"
|
||||
)
|
||||
|
||||
func lookupLocalAddr(ifaceName string, network string, destination net.IP, port int) (net.Addr, error) {
|
||||
func lookupLocalAddr(ifaceName string, network string, destination netip.Addr, port int) (net.Addr, error) {
|
||||
ifaceObj, err := iface.ResolveInterface(ifaceName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var addr *net.IPNet
|
||||
var addr *netip.Prefix
|
||||
switch network {
|
||||
case "udp4", "tcp4":
|
||||
addr, err = ifaceObj.PickIPv4Addr(destination)
|
||||
case "tcp6", "udp6":
|
||||
addr, err = ifaceObj.PickIPv6Addr(destination)
|
||||
default:
|
||||
if destination != nil {
|
||||
if destination.To4() != nil {
|
||||
if destination.IsValid() {
|
||||
if destination.Is4() {
|
||||
addr, err = ifaceObj.PickIPv4Addr(destination)
|
||||
} else {
|
||||
addr, err = ifaceObj.PickIPv6Addr(destination)
|
||||
|
@ -39,12 +40,12 @@ func lookupLocalAddr(ifaceName string, network string, destination net.IP, port
|
|||
|
||||
if strings.HasPrefix(network, "tcp") {
|
||||
return &net.TCPAddr{
|
||||
IP: addr.IP,
|
||||
IP: addr.Addr().AsSlice(),
|
||||
Port: port,
|
||||
}, nil
|
||||
} else if strings.HasPrefix(network, "udp") {
|
||||
return &net.UDPAddr{
|
||||
IP: addr.IP,
|
||||
IP: addr.Addr().AsSlice(),
|
||||
Port: port,
|
||||
}, nil
|
||||
}
|
||||
|
@ -52,7 +53,7 @@ func lookupLocalAddr(ifaceName string, network string, destination net.IP, port
|
|||
return nil, iface.ErrAddrNotFound
|
||||
}
|
||||
|
||||
func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination net.IP) error {
|
||||
func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination netip.Addr) error {
|
||||
if !destination.IsGlobalUnicast() {
|
||||
return nil
|
||||
}
|
||||
|
@ -83,7 +84,7 @@ func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, add
|
|||
|
||||
local, _ := strconv.ParseUint(port, 10, 16)
|
||||
|
||||
addr, err := lookupLocalAddr(ifaceName, network, nil, int(local))
|
||||
addr, err := lookupLocalAddr(ifaceName, network, netip.Addr{}, int(local))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/Dreamacro/clash/component/resolver"
|
||||
)
|
||||
|
@ -29,7 +30,7 @@ func DialContext(ctx context.Context, network, address string, options ...Option
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var ip net.IP
|
||||
var ip netip.Addr
|
||||
switch network {
|
||||
case "tcp4", "udp4":
|
||||
if !opt.direct {
|
||||
|
@ -88,7 +89,7 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio
|
|||
return lc.ListenPacket(ctx, network, address)
|
||||
}
|
||||
|
||||
func dialContext(ctx context.Context, network string, destination net.IP, port string, opt *option) (net.Conn, error) {
|
||||
func dialContext(ctx context.Context, network string, destination netip.Addr, port string, opt *option) (net.Conn, error) {
|
||||
dialer := &net.Dialer{}
|
||||
if opt.interfaceName != "" {
|
||||
if err := bindIfaceToDialer(opt.interfaceName, dialer, network, destination); err != nil {
|
||||
|
@ -128,12 +129,12 @@ func dualStackDialContext(ctx context.Context, network, address string, opt *opt
|
|||
case results <- result:
|
||||
case <-returned:
|
||||
if result.Conn != nil {
|
||||
result.Conn.Close()
|
||||
_ = result.Conn.Close()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var ip net.IP
|
||||
var ip netip.Addr
|
||||
if ipv6 {
|
||||
if !direct {
|
||||
ip, result.error = resolver.ResolveIPv6ProxyServerHost(host)
|
||||
|
|
|
@ -4,14 +4,15 @@ package dialer
|
|||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func bindMarkToDialer(mark int, dialer *net.Dialer, _ string, _ net.IP) {
|
||||
func bindMarkToDialer(mark int, dialer *net.Dialer, _ string, _ netip.Addr) {
|
||||
dialer.Control = bindMarkToControl(mark, dialer.Control)
|
||||
}
|
||||
|
||||
func bindMarkToListenConfig(mark int, lc *net.ListenConfig, _, address string) {
|
||||
func bindMarkToListenConfig(mark int, lc *net.ListenConfig, _, _ string) {
|
||||
lc.Control = bindMarkToControl(mark, lc.Control)
|
||||
}
|
||||
|
||||
|
@ -23,20 +24,17 @@ func bindMarkToControl(mark int, chain controlFn) controlFn {
|
|||
}
|
||||
}()
|
||||
|
||||
ipStr, _, err := net.SplitHostPort(address)
|
||||
if err == nil {
|
||||
ip := net.ParseIP(ipStr)
|
||||
if ip != nil && !ip.IsGlobalUnicast() {
|
||||
addrPort, err := netip.ParseAddrPort(address)
|
||||
if err == nil && !addrPort.Addr().IsGlobalUnicast() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return c.Control(func(fd uintptr) {
|
||||
switch network {
|
||||
case "tcp4", "udp4":
|
||||
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark)
|
||||
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark)
|
||||
case "tcp6", "udp6":
|
||||
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark)
|
||||
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ package dialer
|
|||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
||||
"github.com/Dreamacro/clash/log"
|
||||
|
@ -17,10 +18,10 @@ func printMarkWarn() {
|
|||
})
|
||||
}
|
||||
|
||||
func bindMarkToDialer(mark int, dialer *net.Dialer, _ string, _ net.IP) {
|
||||
func bindMarkToDialer(mark int, dialer *net.Dialer, _ string, _ netip.Addr) {
|
||||
printMarkWarn()
|
||||
}
|
||||
|
||||
func bindMarkToListenConfig(mark int, lc *net.ListenConfig, _, address string) {
|
||||
func bindMarkToListenConfig(mark int, lc *net.ListenConfig, _, _ string) {
|
||||
printMarkWarn()
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package dialer
|
|||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -18,9 +19,9 @@ func resolverDialContext(ctx context.Context, network, address string) (net.Conn
|
|||
interfaceName := DefaultInterface.Load()
|
||||
|
||||
if interfaceName != "" {
|
||||
dstIP := net.ParseIP(address)
|
||||
if dstIP != nil {
|
||||
bindIfaceToDialer(interfaceName, d, network, dstIP)
|
||||
dstIP, err := netip.ParseAddr(address)
|
||||
if err == nil {
|
||||
_ = bindIfaceToDialer(interfaceName, d, network, dstIP)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package iface
|
|||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/common/singledo"
|
||||
|
@ -11,7 +12,7 @@ import (
|
|||
type Interface struct {
|
||||
Index int
|
||||
Name string
|
||||
Addrs []*net.IPNet
|
||||
Addrs []*netip.Prefix
|
||||
HardwareAddr net.HardwareAddr
|
||||
}
|
||||
|
||||
|
@ -37,14 +38,18 @@ func ResolveInterface(name string) (*Interface, error) {
|
|||
continue
|
||||
}
|
||||
|
||||
ipNets := make([]*net.IPNet, 0, len(addrs))
|
||||
ipNets := make([]*netip.Prefix, 0, len(addrs))
|
||||
for _, addr := range addrs {
|
||||
ipNet := addr.(*net.IPNet)
|
||||
if v4 := ipNet.IP.To4(); v4 != nil {
|
||||
ipNet.IP = v4
|
||||
ip, _ := netip.AddrFromSlice(ipNet.IP)
|
||||
|
||||
ones, bits := ipNet.Mask.Size()
|
||||
if bits == 32 {
|
||||
ip = ip.Unmap()
|
||||
}
|
||||
|
||||
ipNets = append(ipNets, ipNet)
|
||||
pf := netip.PrefixFrom(ip, ones)
|
||||
ipNets = append(ipNets, &pf)
|
||||
}
|
||||
|
||||
r[iface.Name] = &Interface{
|
||||
|
@ -74,35 +79,35 @@ func FlushCache() {
|
|||
interfaces.Reset()
|
||||
}
|
||||
|
||||
func (iface *Interface) PickIPv4Addr(destination net.IP) (*net.IPNet, error) {
|
||||
return iface.pickIPAddr(destination, func(addr *net.IPNet) bool {
|
||||
return addr.IP.To4() != nil
|
||||
func (iface *Interface) PickIPv4Addr(destination netip.Addr) (*netip.Prefix, error) {
|
||||
return iface.pickIPAddr(destination, func(addr *netip.Prefix) bool {
|
||||
return addr.Addr().Is4()
|
||||
})
|
||||
}
|
||||
|
||||
func (iface *Interface) PickIPv6Addr(destination net.IP) (*net.IPNet, error) {
|
||||
return iface.pickIPAddr(destination, func(addr *net.IPNet) bool {
|
||||
return addr.IP.To4() == nil
|
||||
func (iface *Interface) PickIPv6Addr(destination netip.Addr) (*netip.Prefix, error) {
|
||||
return iface.pickIPAddr(destination, func(addr *netip.Prefix) bool {
|
||||
return addr.Addr().Is6()
|
||||
})
|
||||
}
|
||||
|
||||
func (iface *Interface) pickIPAddr(destination net.IP, accept func(addr *net.IPNet) bool) (*net.IPNet, error) {
|
||||
var fallback *net.IPNet
|
||||
func (iface *Interface) pickIPAddr(destination netip.Addr, accept func(addr *netip.Prefix) bool) (*netip.Prefix, error) {
|
||||
var fallback *netip.Prefix
|
||||
|
||||
for _, addr := range iface.Addrs {
|
||||
if !accept(addr) {
|
||||
continue
|
||||
}
|
||||
|
||||
if fallback == nil && !addr.IP.IsLinkLocalUnicast() {
|
||||
if fallback == nil && !addr.Addr().IsLinkLocalUnicast() {
|
||||
fallback = addr
|
||||
|
||||
if destination == nil {
|
||||
if !destination.IsValid() {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if destination != nil && addr.Contains(destination) {
|
||||
if destination.IsValid() && addr.Contains(destination) {
|
||||
return addr, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@ package process
|
|||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
"runtime"
|
||||
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
)
|
||||
|
||||
|
@ -19,7 +21,7 @@ const (
|
|||
UDP = "udp"
|
||||
)
|
||||
|
||||
func FindProcessName(network string, srcIP net.IP, srcPort int) (string, error) {
|
||||
func FindProcessName(network string, srcIP netip.Addr, srcPort int) (string, error) {
|
||||
return findProcessName(network, srcIP, srcPort)
|
||||
}
|
||||
|
||||
|
@ -31,23 +33,23 @@ func ShouldFindProcess(metadata *C.Metadata) bool {
|
|||
return false
|
||||
}
|
||||
for _, ip := range localIPs {
|
||||
if ip.Equal(metadata.SrcIP) {
|
||||
if ip == metadata.SrcIP {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func AppendLocalIPs(ip ...net.IP) {
|
||||
func AppendLocalIPs(ip ...netip.Addr) {
|
||||
localIPs = append(ip, localIPs...)
|
||||
}
|
||||
|
||||
func getLocalIPs() []net.IP {
|
||||
ips := []net.IP{net.IPv4zero, net.IPv6zero}
|
||||
func getLocalIPs() []netip.Addr {
|
||||
ips := []netip.Addr{netip.IPv4Unspecified(), netip.IPv6Unspecified()}
|
||||
|
||||
netInterfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
ips = append(ips, net.IPv4(127, 0, 0, 1), net.IPv6loopback)
|
||||
ips = append(ips, netip.AddrFrom4([4]byte{127, 0, 0, 1}), nnip.IpToAddr(net.IPv6loopback))
|
||||
return ips
|
||||
}
|
||||
|
||||
|
@ -57,7 +59,7 @@ func getLocalIPs() []net.IP {
|
|||
|
||||
for _, address := range adds {
|
||||
if ipNet, ok := address.(*net.IPNet); ok {
|
||||
ips = append(ips, ipNet.IP)
|
||||
ips = append(ips, nnip.IpToAddr(ipNet.IP))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +68,7 @@ func getLocalIPs() []net.IP {
|
|||
return ips
|
||||
}
|
||||
|
||||
var localIPs []net.IP
|
||||
var localIPs []netip.Addr
|
||||
|
||||
func init() {
|
||||
localIPs = getLocalIPs()
|
||||
|
|
|
@ -2,10 +2,12 @@ package process
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"net"
|
||||
"net/netip"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
|
@ -15,7 +17,7 @@ const (
|
|||
proccallnumpidinfo = 0x2
|
||||
)
|
||||
|
||||
func findProcessName(network string, ip net.IP, port int) (string, error) {
|
||||
func findProcessName(network string, ip netip.Addr, port int) (string, error) {
|
||||
var spath string
|
||||
switch network {
|
||||
case TCP:
|
||||
|
@ -26,7 +28,7 @@ func findProcessName(network string, ip net.IP, port int) (string, error) {
|
|||
return "", ErrInvalidNetwork
|
||||
}
|
||||
|
||||
isIPv4 := ip.To4() != nil
|
||||
isIPv4 := ip.Is4()
|
||||
|
||||
value, err := syscall.Sysctl(spath)
|
||||
if err != nil {
|
||||
|
@ -57,19 +59,19 @@ func findProcessName(network string, ip net.IP, port int) (string, error) {
|
|||
// xinpcb_n.inp_vflag
|
||||
flag := buf[inp+44]
|
||||
|
||||
var srcIP net.IP
|
||||
var srcIP netip.Addr
|
||||
switch {
|
||||
case flag&0x1 > 0 && isIPv4:
|
||||
// ipv4
|
||||
srcIP = net.IP(buf[inp+76 : inp+80])
|
||||
srcIP = nnip.IpToAddr(buf[inp+76 : inp+80])
|
||||
case flag&0x2 > 0 && !isIPv4:
|
||||
// ipv6
|
||||
srcIP = net.IP(buf[inp+64 : inp+80])
|
||||
srcIP = nnip.IpToAddr(buf[inp+64 : inp+80])
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
if !ip.Equal(srcIP) && (network == TCP || !srcIP.IsUnspecified()) {
|
||||
if ip != srcIP && (network == TCP || !srcIP.IsUnspecified()) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -3,13 +3,14 @@ package process
|
|||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
)
|
||||
|
||||
|
@ -20,7 +21,7 @@ var (
|
|||
once sync.Once
|
||||
)
|
||||
|
||||
func findProcessName(network string, ip net.IP, srcPort int) (string, error) {
|
||||
func findProcessName(network string, ip netip.Addr, srcPort int) (string, error) {
|
||||
once.Do(func() {
|
||||
if err := initSearcher(); err != nil {
|
||||
log.Errorln("Initialize PROCESS-NAME failed: %s", err.Error())
|
||||
|
@ -102,7 +103,7 @@ type searcher struct {
|
|||
pid int
|
||||
}
|
||||
|
||||
func (s *searcher) Search(buf []byte, ip net.IP, port uint16, isTCP bool) (uint32, error) {
|
||||
func (s *searcher) Search(buf []byte, ip netip.Addr, port uint16, isTCP bool) (uint32, error) {
|
||||
var itemSize int
|
||||
var inpOffset int
|
||||
|
||||
|
@ -116,7 +117,7 @@ func (s *searcher) Search(buf []byte, ip net.IP, port uint16, isTCP bool) (uint3
|
|||
inpOffset = s.udpInpOffset
|
||||
}
|
||||
|
||||
isIPv4 := ip.To4() != nil
|
||||
isIPv4 := ip.Is4()
|
||||
// skip the first xinpgen block
|
||||
for i := s.headSize; i+itemSize <= len(buf); i += itemSize {
|
||||
inp := i + inpOffset
|
||||
|
@ -130,19 +131,19 @@ func (s *searcher) Search(buf []byte, ip net.IP, port uint16, isTCP bool) (uint3
|
|||
// xinpcb.inp_vflag
|
||||
flag := buf[inp+s.vflag]
|
||||
|
||||
var srcIP net.IP
|
||||
var srcIP netip.Addr
|
||||
switch {
|
||||
case flag&0x1 > 0 && isIPv4:
|
||||
// ipv4
|
||||
srcIP = net.IP(buf[inp+s.ip : inp+s.ip+4])
|
||||
srcIP = nnip.IpToAddr(buf[inp+s.ip : inp+s.ip+4])
|
||||
case flag&0x2 > 0 && !isIPv4:
|
||||
// ipv6
|
||||
srcIP = net.IP(buf[inp+s.ip-12 : inp+s.ip+4])
|
||||
srcIP = nnip.IpToAddr(buf[inp+s.ip-12 : inp+s.ip+4])
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
if !ip.Equal(srcIP) {
|
||||
if ip != srcIP {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
@ -31,7 +32,7 @@ const (
|
|||
pathProc = "/proc"
|
||||
)
|
||||
|
||||
func findProcessName(network string, ip net.IP, srcPort int) (string, error) {
|
||||
func findProcessName(network string, ip netip.Addr, srcPort int) (string, error) {
|
||||
inode, uid, err := resolveSocketByNetlink(network, ip, srcPort)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -40,7 +41,7 @@ func findProcessName(network string, ip net.IP, srcPort int) (string, error) {
|
|||
return resolveProcessNameByProcSearch(inode, uid)
|
||||
}
|
||||
|
||||
func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int32, error) {
|
||||
func resolveSocketByNetlink(network string, ip netip.Addr, srcPort int) (int32, int32, error) {
|
||||
var family byte
|
||||
var protocol byte
|
||||
|
||||
|
@ -53,7 +54,7 @@ func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int3
|
|||
return 0, 0, ErrInvalidNetwork
|
||||
}
|
||||
|
||||
if ip.To4() != nil {
|
||||
if ip.Is4() {
|
||||
family = syscall.AF_INET
|
||||
} else {
|
||||
family = syscall.AF_INET6
|
||||
|
@ -65,10 +66,12 @@ func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int3
|
|||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("dial netlink: %w", err)
|
||||
}
|
||||
defer syscall.Close(socket)
|
||||
defer func() {
|
||||
_ = syscall.Close(socket)
|
||||
}()
|
||||
|
||||
syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &syscall.Timeval{Usec: 100})
|
||||
syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &syscall.Timeval{Usec: 100})
|
||||
_ = syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &syscall.Timeval{Usec: 100})
|
||||
_ = syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &syscall.Timeval{Usec: 100})
|
||||
|
||||
if err := syscall.Connect(socket, &syscall.SockaddrNetlink{
|
||||
Family: syscall.AF_NETLINK,
|
||||
|
@ -84,7 +87,9 @@ func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int3
|
|||
}
|
||||
|
||||
rb := pool.Get(pool.RelayBufferSize)
|
||||
defer pool.Put(rb)
|
||||
defer func() {
|
||||
_ = pool.Put(rb)
|
||||
}()
|
||||
|
||||
n, err := syscall.Read(socket, rb)
|
||||
if err != nil {
|
||||
|
@ -111,14 +116,10 @@ func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int3
|
|||
return inode, uid, nil
|
||||
}
|
||||
|
||||
func packSocketDiagRequest(family, protocol byte, source net.IP, sourcePort uint16) []byte {
|
||||
func packSocketDiagRequest(family, protocol byte, source netip.Addr, sourcePort uint16) []byte {
|
||||
s := make([]byte, 16)
|
||||
|
||||
if v4 := source.To4(); v4 != nil {
|
||||
copy(s, v4)
|
||||
} else {
|
||||
copy(s, source)
|
||||
}
|
||||
copy(s, source.AsSlice())
|
||||
|
||||
buf := make([]byte, sizeOfSocketDiagRequest)
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
package process
|
||||
|
||||
import "net"
|
||||
import "net/netip"
|
||||
|
||||
func findProcessName(network string, ip net.IP, srcPort int) (string, error) {
|
||||
func findProcessName(network string, ip netip.Addr, srcPort int) (string, error) {
|
||||
return "", ErrPlatformNotSupport
|
||||
}
|
||||
|
|
|
@ -2,11 +2,12 @@ package process
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
@ -57,7 +58,7 @@ func initWin32API() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func findProcessName(network string, ip net.IP, srcPort int) (string, error) {
|
||||
func findProcessName(network string, ip netip.Addr, srcPort int) (string, error) {
|
||||
once.Do(func() {
|
||||
err := initWin32API()
|
||||
if err != nil {
|
||||
|
@ -67,7 +68,7 @@ func findProcessName(network string, ip net.IP, srcPort int) (string, error) {
|
|||
}
|
||||
})
|
||||
family := windows.AF_INET
|
||||
if ip.To4() == nil {
|
||||
if ip.Is6() {
|
||||
family = windows.AF_INET6
|
||||
}
|
||||
|
||||
|
@ -107,7 +108,7 @@ type searcher struct {
|
|||
tcpState int
|
||||
}
|
||||
|
||||
func (s *searcher) Search(b []byte, ip net.IP, port uint16) (uint32, error) {
|
||||
func (s *searcher) Search(b []byte, ip netip.Addr, port uint16) (uint32, error) {
|
||||
n := int(readNativeUint32(b[:4]))
|
||||
itemSize := s.itemSize
|
||||
for i := 0; i < n; i++ {
|
||||
|
@ -131,9 +132,9 @@ func (s *searcher) Search(b []byte, ip net.IP, port uint16) (uint32, error) {
|
|||
continue
|
||||
}
|
||||
|
||||
srcIP := net.IP(row[s.ip : s.ip+s.ipSize])
|
||||
srcIP := nnip.IpToAddr(row[s.ip : s.ip+s.ipSize])
|
||||
// windows binds an unbound udp socket to 0.0.0.0/[::] while first sendto
|
||||
if !ip.Equal(srcIP) && (!srcIP.IsUnspecified() || s.tcpState != -1) {
|
||||
if ip != srcIP && (!srcIP.IsUnspecified() || s.tcpState != -1) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
package resolver
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
import "net/netip"
|
||||
|
||||
var DefaultHostMapper Enhancer
|
||||
|
||||
type Enhancer interface {
|
||||
FakeIPEnabled() bool
|
||||
MappingEnabled() bool
|
||||
IsFakeIP(net.IP) bool
|
||||
IsFakeBroadcastIP(net.IP) bool
|
||||
IsExistFakeIP(net.IP) bool
|
||||
FindHostByIP(net.IP) (string, bool)
|
||||
IsFakeIP(netip.Addr) bool
|
||||
IsFakeBroadcastIP(netip.Addr) bool
|
||||
IsExistFakeIP(netip.Addr) bool
|
||||
FindHostByIP(netip.Addr) (string, bool)
|
||||
FlushFakeIP() error
|
||||
InsertHostByIP(net.IP, string)
|
||||
InsertHostByIP(netip.Addr, string)
|
||||
StoreFakePoolState()
|
||||
}
|
||||
|
||||
|
@ -34,7 +32,7 @@ func MappingEnabled() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func IsFakeIP(ip net.IP) bool {
|
||||
func IsFakeIP(ip netip.Addr) bool {
|
||||
if mapper := DefaultHostMapper; mapper != nil {
|
||||
return mapper.IsFakeIP(ip)
|
||||
}
|
||||
|
@ -42,7 +40,7 @@ func IsFakeIP(ip net.IP) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func IsFakeBroadcastIP(ip net.IP) bool {
|
||||
func IsFakeBroadcastIP(ip netip.Addr) bool {
|
||||
if mapper := DefaultHostMapper; mapper != nil {
|
||||
return mapper.IsFakeBroadcastIP(ip)
|
||||
}
|
||||
|
@ -50,7 +48,7 @@ func IsFakeBroadcastIP(ip net.IP) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func IsExistFakeIP(ip net.IP) bool {
|
||||
func IsExistFakeIP(ip netip.Addr) bool {
|
||||
if mapper := DefaultHostMapper; mapper != nil {
|
||||
return mapper.IsExistFakeIP(ip)
|
||||
}
|
||||
|
@ -58,13 +56,13 @@ func IsExistFakeIP(ip net.IP) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func InsertHostByIP(ip net.IP, host string) {
|
||||
func InsertHostByIP(ip netip.Addr, host string) {
|
||||
if mapper := DefaultHostMapper; mapper != nil {
|
||||
mapper.InsertHostByIP(ip, host)
|
||||
}
|
||||
}
|
||||
|
||||
func FindHostByIP(ip net.IP) (string, bool) {
|
||||
func FindHostByIP(ip netip.Addr) (string, bool) {
|
||||
if mapper := DefaultHostMapper; mapper != nil {
|
||||
return mapper.FindHostByIP(ip)
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ import (
|
|||
"math/rand"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
"github.com/Dreamacro/clash/component/trie"
|
||||
)
|
||||
|
||||
|
@ -37,29 +37,29 @@ var (
|
|||
)
|
||||
|
||||
type Resolver interface {
|
||||
ResolveIP(host string) (ip net.IP, err error)
|
||||
ResolveIPv4(host string) (ip net.IP, err error)
|
||||
ResolveIPv6(host string) (ip net.IP, err error)
|
||||
ResolveIP(host string) (ip netip.Addr, err error)
|
||||
ResolveIPv4(host string) (ip netip.Addr, err error)
|
||||
ResolveIPv6(host string) (ip netip.Addr, err error)
|
||||
}
|
||||
|
||||
// ResolveIPv4 with a host, return ipv4
|
||||
func ResolveIPv4(host string) (net.IP, error) {
|
||||
func ResolveIPv4(host string) (netip.Addr, error) {
|
||||
return ResolveIPv4WithResolver(host, DefaultResolver)
|
||||
}
|
||||
|
||||
func ResolveIPv4WithResolver(host string, r Resolver) (net.IP, error) {
|
||||
func ResolveIPv4WithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||
if node := DefaultHosts.Search(host); node != nil {
|
||||
if ip := node.Data; ip.Is4() {
|
||||
return ip.AsSlice(), nil
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
|
||||
ip := net.ParseIP(host)
|
||||
if ip != nil {
|
||||
if !strings.Contains(host, ":") {
|
||||
ip, err := netip.ParseAddr(host)
|
||||
if err == nil {
|
||||
if ip.Is4() {
|
||||
return ip, nil
|
||||
}
|
||||
return nil, ErrIPVersion
|
||||
return netip.Addr{}, ErrIPVersion
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
|
@ -71,39 +71,44 @@ func ResolveIPv4WithResolver(host string, r Resolver) (net.IP, error) {
|
|||
defer cancel()
|
||||
ipAddrs, err := net.DefaultResolver.LookupIP(ctx, "ip4", host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return netip.Addr{}, err
|
||||
} else if len(ipAddrs) == 0 {
|
||||
return nil, ErrIPNotFound
|
||||
return netip.Addr{}, ErrIPNotFound
|
||||
}
|
||||
|
||||
return ipAddrs[rand.Intn(len(ipAddrs))], nil
|
||||
ip := ipAddrs[rand.Intn(len(ipAddrs))].To4()
|
||||
if ip == nil {
|
||||
return netip.Addr{}, ErrIPVersion
|
||||
}
|
||||
|
||||
return nil, ErrIPNotFound
|
||||
return netip.AddrFrom4(*(*[4]byte)(ip)), nil
|
||||
}
|
||||
|
||||
return netip.Addr{}, ErrIPNotFound
|
||||
}
|
||||
|
||||
// ResolveIPv6 with a host, return ipv6
|
||||
func ResolveIPv6(host string) (net.IP, error) {
|
||||
func ResolveIPv6(host string) (netip.Addr, error) {
|
||||
return ResolveIPv6WithResolver(host, DefaultResolver)
|
||||
}
|
||||
|
||||
func ResolveIPv6WithResolver(host string, r Resolver) (net.IP, error) {
|
||||
func ResolveIPv6WithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||
if DisableIPv6 {
|
||||
return nil, ErrIPv6Disabled
|
||||
return netip.Addr{}, ErrIPv6Disabled
|
||||
}
|
||||
|
||||
if node := DefaultHosts.Search(host); node != nil {
|
||||
if ip := node.Data; ip.Is6() {
|
||||
return ip.AsSlice(), nil
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
|
||||
ip := net.ParseIP(host)
|
||||
if ip != nil {
|
||||
if strings.Contains(host, ":") {
|
||||
ip, err := netip.ParseAddr(host)
|
||||
if err == nil {
|
||||
if ip.Is6() {
|
||||
return ip, nil
|
||||
}
|
||||
return nil, ErrIPVersion
|
||||
return netip.Addr{}, ErrIPVersion
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
|
@ -115,22 +120,21 @@ func ResolveIPv6WithResolver(host string, r Resolver) (net.IP, error) {
|
|||
defer cancel()
|
||||
ipAddrs, err := net.DefaultResolver.LookupIP(ctx, "ip6", host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return netip.Addr{}, err
|
||||
} else if len(ipAddrs) == 0 {
|
||||
return nil, ErrIPNotFound
|
||||
return netip.Addr{}, ErrIPNotFound
|
||||
}
|
||||
|
||||
return ipAddrs[rand.Intn(len(ipAddrs))], nil
|
||||
return netip.AddrFrom16(*(*[16]byte)(ipAddrs[rand.Intn(len(ipAddrs))])), nil
|
||||
}
|
||||
|
||||
return nil, ErrIPNotFound
|
||||
return netip.Addr{}, ErrIPNotFound
|
||||
}
|
||||
|
||||
// ResolveIPWithResolver same as ResolveIP, but with a resolver
|
||||
func ResolveIPWithResolver(host string, r Resolver) (net.IP, error) {
|
||||
func ResolveIPWithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||
if node := DefaultHosts.Search(host); node != nil {
|
||||
ip := node.Data
|
||||
return ip.Unmap().AsSlice(), nil
|
||||
return node.Data, nil
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
|
@ -142,30 +146,30 @@ func ResolveIPWithResolver(host string, r Resolver) (net.IP, error) {
|
|||
return ResolveIPv4(host)
|
||||
}
|
||||
|
||||
ip := net.ParseIP(host)
|
||||
if ip != nil {
|
||||
ip, err := netip.ParseAddr(host)
|
||||
if err == nil {
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
if DefaultResolver == nil {
|
||||
ipAddr, err := net.ResolveIPAddr("ip", host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return netip.Addr{}, err
|
||||
}
|
||||
|
||||
return ipAddr.IP, nil
|
||||
return nnip.IpToAddr(ipAddr.IP), nil
|
||||
}
|
||||
|
||||
return nil, ErrIPNotFound
|
||||
return netip.Addr{}, ErrIPNotFound
|
||||
}
|
||||
|
||||
// ResolveIP with a host, return ip
|
||||
func ResolveIP(host string) (net.IP, error) {
|
||||
func ResolveIP(host string) (netip.Addr, error) {
|
||||
return ResolveIPWithResolver(host, DefaultResolver)
|
||||
}
|
||||
|
||||
// ResolveIPv4ProxyServerHost proxies server host only
|
||||
func ResolveIPv4ProxyServerHost(host string) (net.IP, error) {
|
||||
func ResolveIPv4ProxyServerHost(host string) (netip.Addr, error) {
|
||||
if ProxyServerHostResolver != nil {
|
||||
return ResolveIPv4WithResolver(host, ProxyServerHostResolver)
|
||||
}
|
||||
|
@ -173,7 +177,7 @@ func ResolveIPv4ProxyServerHost(host string) (net.IP, error) {
|
|||
}
|
||||
|
||||
// ResolveIPv6ProxyServerHost proxies server host only
|
||||
func ResolveIPv6ProxyServerHost(host string) (net.IP, error) {
|
||||
func ResolveIPv6ProxyServerHost(host string) (netip.Addr, error) {
|
||||
if ProxyServerHostResolver != nil {
|
||||
return ResolveIPv6WithResolver(host, ProxyServerHostResolver)
|
||||
}
|
||||
|
@ -181,7 +185,7 @@ func ResolveIPv6ProxyServerHost(host string) (net.IP, error) {
|
|||
}
|
||||
|
||||
// ResolveProxyServerHost proxies server host only
|
||||
func ResolveProxyServerHost(host string) (net.IP, error) {
|
||||
func ResolveProxyServerHost(host string) (netip.Addr, error) {
|
||||
if ProxyServerHostResolver != nil {
|
||||
return ResolveIPWithResolver(host, ProxyServerHostResolver)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
"github.com/Dreamacro/clash/component/trie"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
CN "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/component/resolver"
|
||||
|
@ -58,7 +59,7 @@ func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string) {
|
|||
metadata.Host = host
|
||||
metadata.DNSMode = C.DNSMapping
|
||||
resolver.InsertHostByIP(metadata.DstIP, host)
|
||||
metadata.DstIP = nil
|
||||
metadata.DstIP = netip.Addr{}
|
||||
}
|
||||
|
||||
func (sd *SnifferDispatcher) Enable() bool {
|
||||
|
|
|
@ -87,7 +87,7 @@ type DNS struct {
|
|||
type FallbackFilter struct {
|
||||
GeoIP bool `yaml:"geoip"`
|
||||
GeoIPCode string `yaml:"geoip-code"`
|
||||
IPCIDR []*net.IPNet `yaml:"ipcidr"`
|
||||
IPCIDR []*netip.Prefix `yaml:"ipcidr"`
|
||||
Domain []string `yaml:"domain"`
|
||||
GeoSite []*router.DomainMatcher `yaml:"geosite"`
|
||||
}
|
||||
|
@ -702,15 +702,15 @@ func parseNameServerPolicy(nsPolicy map[string]string) (map[string]dns.NameServe
|
|||
return policy, nil
|
||||
}
|
||||
|
||||
func parseFallbackIPCIDR(ips []string) ([]*net.IPNet, error) {
|
||||
var ipNets []*net.IPNet
|
||||
func parseFallbackIPCIDR(ips []string) ([]*netip.Prefix, error) {
|
||||
var ipNets []*netip.Prefix
|
||||
|
||||
for idx, ip := range ips {
|
||||
_, ipnet, err := net.ParseCIDR(ip)
|
||||
ipnet, err := netip.ParsePrefix(ip)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DNS FallbackIP[%d] format error: %s", idx, err.Error())
|
||||
}
|
||||
ipNets = append(ipNets, ipnet)
|
||||
ipNets = append(ipNets, &ipnet)
|
||||
}
|
||||
|
||||
return ipNets, nil
|
||||
|
@ -763,7 +763,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[netip.Addr], rules []C.R
|
|||
IPv6: cfg.IPv6,
|
||||
EnhancedMode: cfg.EnhancedMode,
|
||||
FallbackFilter: FallbackFilter{
|
||||
IPCIDR: []*net.IPNet{},
|
||||
IPCIDR: []*netip.Prefix{},
|
||||
GeoSite: []*router.DomainMatcher{},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
@ -75,8 +76,8 @@ func (t Type) MarshalJSON() ([]byte, error) {
|
|||
type Metadata struct {
|
||||
NetWork NetWork `json:"network"`
|
||||
Type Type `json:"type"`
|
||||
SrcIP net.IP `json:"sourceIP"`
|
||||
DstIP net.IP `json:"destinationIP"`
|
||||
SrcIP netip.Addr `json:"sourceIP"`
|
||||
DstIP netip.Addr `json:"destinationIP"`
|
||||
SrcPort string `json:"sourcePort"`
|
||||
DstPort string `json:"destinationPort"`
|
||||
AddrType int `json:"-"`
|
||||
|
@ -84,11 +85,15 @@ type Metadata struct {
|
|||
DNSMode DNSMode `json:"dnsMode"`
|
||||
Process string `json:"process"`
|
||||
ProcessPath string `json:"processPath"`
|
||||
UserAgent string `json:"userAgent"`
|
||||
}
|
||||
|
||||
func (m *Metadata) RemoteAddress() string {
|
||||
if m.DstIP.IsValid() {
|
||||
return net.JoinHostPort(m.DstIP.String(), m.DstPort)
|
||||
} else {
|
||||
return net.JoinHostPort(m.String(), m.DstPort)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Metadata) SourceAddress() string {
|
||||
|
@ -108,33 +113,33 @@ func (m *Metadata) SourceDetail() string {
|
|||
}
|
||||
|
||||
func (m *Metadata) Resolved() bool {
|
||||
return m.DstIP != nil
|
||||
return m.DstIP.IsValid()
|
||||
}
|
||||
|
||||
// Pure is used to solve unexpected behavior
|
||||
// when dialing proxy connection in DNSMapping mode.
|
||||
func (m *Metadata) Pure() *Metadata {
|
||||
if m.DNSMode == DNSMapping && m.DstIP != nil {
|
||||
copy := *m
|
||||
copy.Host = ""
|
||||
if copy.DstIP.To4() != nil {
|
||||
copy.AddrType = AtypIPv4
|
||||
if m.DNSMode == DNSMapping && m.DstIP.IsValid() {
|
||||
copyM := *m
|
||||
copyM.Host = ""
|
||||
if copyM.DstIP.Is4() {
|
||||
copyM.AddrType = AtypIPv4
|
||||
} else {
|
||||
copy.AddrType = AtypIPv6
|
||||
copyM.AddrType = AtypIPv6
|
||||
}
|
||||
return ©
|
||||
return ©M
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Metadata) UDPAddr() *net.UDPAddr {
|
||||
if m.NetWork != UDP || m.DstIP == nil {
|
||||
if m.NetWork != UDP || !m.DstIP.IsValid() {
|
||||
return nil
|
||||
}
|
||||
port, _ := strconv.ParseUint(m.DstPort, 10, 16)
|
||||
return &net.UDPAddr{
|
||||
IP: m.DstIP,
|
||||
IP: m.DstIP.AsSlice(),
|
||||
Port: int(port),
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +147,7 @@ func (m *Metadata) UDPAddr() *net.UDPAddr {
|
|||
func (m *Metadata) String() string {
|
||||
if m.Host != "" {
|
||||
return m.Host
|
||||
} else if m.DstIP != nil {
|
||||
} else if m.DstIP.IsValid() {
|
||||
return m.DstIP.String()
|
||||
} else {
|
||||
return "<nil>"
|
||||
|
@ -150,5 +155,5 @@ func (m *Metadata) String() string {
|
|||
}
|
||||
|
||||
func (m *Metadata) Valid() bool {
|
||||
return m.Host != "" || m.DstIP != nil
|
||||
return m.Host != "" || m.DstIP.IsValid()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package constant
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
|
||||
"github.com/Dreamacro/clash/component/geodata/router"
|
||||
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
type RuleExtra struct {
|
||||
Network NetWork
|
||||
SourceIPs []*net.IPNet
|
||||
SourceIPs []*netip.Prefix
|
||||
ProcessNames []string
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ func (re *RuleExtra) NotMatchNetwork(network NetWork) bool {
|
|||
return re.Network != ALLNet && re.Network != network
|
||||
}
|
||||
|
||||
func (re *RuleExtra) NotMatchSourceIP(srcIP net.IP) bool {
|
||||
func (re *RuleExtra) NotMatchSourceIP(srcIP netip.Addr) bool {
|
||||
if re.SourceIPs == nil {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
|
@ -28,10 +29,10 @@ func (c *client) Exchange(m *D.Msg) (*D.Msg, error) {
|
|||
|
||||
func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) {
|
||||
var (
|
||||
ip net.IP
|
||||
ip netip.Addr
|
||||
err error
|
||||
)
|
||||
if ip = net.ParseIP(c.host); ip == nil {
|
||||
if ip, err = netip.ParseAddr(c.host); err != nil {
|
||||
if c.r == nil {
|
||||
return nil, fmt.Errorf("dns %s not a valid ip", c.host)
|
||||
} else {
|
||||
|
@ -62,7 +63,9 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error)
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
defer func() {
|
||||
_ = conn.Close()
|
||||
}()
|
||||
|
||||
// miekg/dns ExchangeContext doesn't respond to context cancel.
|
||||
// this is a workaround
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -27,7 +27,7 @@ type dhcpClient struct {
|
|||
ifaceInvalidate time.Time
|
||||
dnsInvalidate time.Time
|
||||
|
||||
ifaceAddr *net.IPNet
|
||||
ifaceAddr *netip.Prefix
|
||||
done chan struct{}
|
||||
resolver *Resolver
|
||||
err error
|
||||
|
@ -127,12 +127,12 @@ func (d *dhcpClient) invalidate() (bool, error) {
|
|||
return false, err
|
||||
}
|
||||
|
||||
addr, err := ifaceObj.PickIPv4Addr(nil)
|
||||
addr, err := ifaceObj.PickIPv4Addr(netip.Addr{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if time.Now().Before(d.dnsInvalidate) && d.ifaceAddr.IP.Equal(addr.IP) && bytes.Equal(d.ifaceAddr.Mask, addr.Mask) {
|
||||
if time.Now().Before(d.dnsInvalidate) && d.ifaceAddr == addr {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/Dreamacro/clash/common/cache"
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
"github.com/Dreamacro/clash/component/fakeip"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
)
|
||||
|
@ -24,54 +22,51 @@ func (h *ResolverEnhancer) MappingEnabled() bool {
|
|||
return h.mode == C.DNSFakeIP || h.mode == C.DNSMapping
|
||||
}
|
||||
|
||||
func (h *ResolverEnhancer) IsExistFakeIP(ip net.IP) bool {
|
||||
func (h *ResolverEnhancer) IsExistFakeIP(ip netip.Addr) bool {
|
||||
if !h.FakeIPEnabled() {
|
||||
return false
|
||||
}
|
||||
|
||||
if pool := h.fakePool; pool != nil {
|
||||
return pool.Exist(nnip.IpToAddr(ip))
|
||||
return pool.Exist(ip)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *ResolverEnhancer) IsFakeIP(ip net.IP) bool {
|
||||
if !h.FakeIPEnabled() {
|
||||
return false
|
||||
}
|
||||
|
||||
addr := nnip.IpToAddr(ip)
|
||||
|
||||
if pool := h.fakePool; pool != nil {
|
||||
return pool.IPNet().Contains(addr) && addr != pool.Gateway() && addr != pool.Broadcast()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *ResolverEnhancer) IsFakeBroadcastIP(ip net.IP) bool {
|
||||
func (h *ResolverEnhancer) IsFakeIP(ip netip.Addr) bool {
|
||||
if !h.FakeIPEnabled() {
|
||||
return false
|
||||
}
|
||||
|
||||
if pool := h.fakePool; pool != nil {
|
||||
return pool.Broadcast() == nnip.IpToAddr(ip)
|
||||
return pool.IPNet().Contains(ip) && ip != pool.Gateway() && ip != pool.Broadcast()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *ResolverEnhancer) FindHostByIP(ip net.IP) (string, bool) {
|
||||
addr := nnip.IpToAddr(ip)
|
||||
func (h *ResolverEnhancer) IsFakeBroadcastIP(ip netip.Addr) bool {
|
||||
if !h.FakeIPEnabled() {
|
||||
return false
|
||||
}
|
||||
|
||||
if pool := h.fakePool; pool != nil {
|
||||
if host, existed := pool.LookBack(addr); existed {
|
||||
return pool.Broadcast() == ip
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *ResolverEnhancer) FindHostByIP(ip netip.Addr) (string, bool) {
|
||||
if pool := h.fakePool; pool != nil {
|
||||
if host, existed := pool.LookBack(ip); existed {
|
||||
return host, true
|
||||
}
|
||||
}
|
||||
|
||||
if mapping := h.mapping; mapping != nil {
|
||||
if host, existed := h.mapping.Get(addr); existed {
|
||||
if host, existed := h.mapping.Get(ip); existed {
|
||||
return host, true
|
||||
}
|
||||
}
|
||||
|
@ -79,9 +74,9 @@ func (h *ResolverEnhancer) FindHostByIP(ip net.IP) (string, bool) {
|
|||
return "", false
|
||||
}
|
||||
|
||||
func (h *ResolverEnhancer) InsertHostByIP(ip net.IP, host string) {
|
||||
func (h *ResolverEnhancer) InsertHostByIP(ip netip.Addr, host string) {
|
||||
if mapping := h.mapping; mapping != nil {
|
||||
h.mapping.Set(nnip.IpToAddr(ip), host)
|
||||
h.mapping.Set(ip, host)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
|
||||
"github.com/Dreamacro/clash/component/geodata"
|
||||
"github.com/Dreamacro/clash/component/geodata/router"
|
||||
"github.com/Dreamacro/clash/component/mmdb"
|
||||
"github.com/Dreamacro/clash/component/trie"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type fallbackIPFilter interface {
|
||||
Match(net.IP) bool
|
||||
Match(netip.Addr) bool
|
||||
}
|
||||
|
||||
type geoipFilter struct {
|
||||
|
@ -21,9 +22,9 @@ type geoipFilter struct {
|
|||
|
||||
var geoIPMatcher *router.GeoIPMatcher
|
||||
|
||||
func (gf *geoipFilter) Match(ip net.IP) bool {
|
||||
func (gf *geoipFilter) Match(ip netip.Addr) bool {
|
||||
if !C.GeodataMode {
|
||||
record, _ := mmdb.Instance().Country(ip)
|
||||
record, _ := mmdb.Instance().Country(ip.AsSlice())
|
||||
return !strings.EqualFold(record.Country.IsoCode, gf.code) && !ip.IsPrivate()
|
||||
}
|
||||
|
||||
|
@ -54,14 +55,14 @@ func (gf *geoipFilter) Match(ip net.IP) bool {
|
|||
return false
|
||||
}
|
||||
}
|
||||
return !geoIPMatcher.Match(ip)
|
||||
return !geoIPMatcher.Match(ip.AsSlice())
|
||||
}
|
||||
|
||||
type ipnetFilter struct {
|
||||
ipnet *net.IPNet
|
||||
ipnet *netip.Prefix
|
||||
}
|
||||
|
||||
func (inf *ipnetFilter) Match(ip net.IP) bool {
|
||||
func (inf *ipnetFilter) Match(ip netip.Addr) bool {
|
||||
return inf.ipnet.Contains(ip)
|
||||
}
|
||||
|
||||
|
@ -76,7 +77,7 @@ type domainFilter struct {
|
|||
func NewDomainFilter(domains []string) *domainFilter {
|
||||
df := domainFilter{tree: trie.New[bool]()}
|
||||
for _, domain := range domains {
|
||||
df.tree.Insert(domain, true)
|
||||
_ = df.tree.Insert(domain, true)
|
||||
}
|
||||
return &df
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -88,21 +87,21 @@ func withMapping(mapping *cache.LruCache[netip.Addr, string]) middleware {
|
|||
host := strings.TrimRight(q.Name, ".")
|
||||
|
||||
for _, ans := range msg.Answer {
|
||||
var ip net.IP
|
||||
var ip netip.Addr
|
||||
var ttl uint32
|
||||
|
||||
switch a := ans.(type) {
|
||||
case *D.A:
|
||||
ip = a.A
|
||||
ip = nnip.IpToAddr(a.A)
|
||||
ttl = a.Hdr.Ttl
|
||||
case *D.AAAA:
|
||||
ip = a.AAAA
|
||||
ip = nnip.IpToAddr(a.AAAA)
|
||||
ttl = a.Hdr.Ttl
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
mapping.SetWithExpire(nnip.IpToAddr(ip), host, time.Now().Add(time.Second*time.Duration(ttl)))
|
||||
mapping.SetWithExpire(ip, host, time.Now().Add(time.Second*time.Duration(ttl)))
|
||||
}
|
||||
|
||||
return msg, nil
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -46,8 +45,8 @@ type Resolver struct {
|
|||
}
|
||||
|
||||
// ResolveIP request with TypeA and TypeAAAA, priority return TypeA
|
||||
func (r *Resolver) ResolveIP(host string) (ip net.IP, err error) {
|
||||
ch := make(chan net.IP, 1)
|
||||
func (r *Resolver) ResolveIP(host string) (ip netip.Addr, err error) {
|
||||
ch := make(chan netip.Addr, 1)
|
||||
go func() {
|
||||
defer close(ch)
|
||||
ip, err := r.resolveIP(host, D.TypeAAAA)
|
||||
|
@ -64,23 +63,23 @@ func (r *Resolver) ResolveIP(host string) (ip net.IP, err error) {
|
|||
|
||||
ip, open := <-ch
|
||||
if !open {
|
||||
return nil, resolver.ErrIPNotFound
|
||||
return netip.Addr{}, resolver.ErrIPNotFound
|
||||
}
|
||||
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
// ResolveIPv4 request with TypeA
|
||||
func (r *Resolver) ResolveIPv4(host string) (ip net.IP, err error) {
|
||||
func (r *Resolver) ResolveIPv4(host string) (ip netip.Addr, err error) {
|
||||
return r.resolveIP(host, D.TypeA)
|
||||
}
|
||||
|
||||
// ResolveIPv6 request with TypeAAAA
|
||||
func (r *Resolver) ResolveIPv6(host string) (ip net.IP, err error) {
|
||||
func (r *Resolver) ResolveIPv6(host string) (ip netip.Addr, err error) {
|
||||
return r.resolveIP(host, D.TypeAAAA)
|
||||
}
|
||||
|
||||
func (r *Resolver) shouldIPFallback(ip net.IP) bool {
|
||||
func (r *Resolver) shouldIPFallback(ip netip.Addr) bool {
|
||||
for _, filter := range r.fallbackIPFilters {
|
||||
if filter.Match(ip) {
|
||||
return true
|
||||
|
@ -101,10 +100,10 @@ func (r *Resolver) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, e
|
|||
}
|
||||
|
||||
q := m.Question[0]
|
||||
cache, expireTime, hit := r.lruCache.GetWithExpire(q.String())
|
||||
cacheM, expireTime, hit := r.lruCache.GetWithExpire(q.String())
|
||||
if hit {
|
||||
now := time.Now()
|
||||
msg = cache.Copy()
|
||||
msg = cacheM.Copy()
|
||||
if expireTime.Before(now) {
|
||||
setMsgTTL(msg, uint32(1)) // Continue fetch
|
||||
go r.exchangeWithoutCache(ctx, m)
|
||||
|
@ -255,16 +254,16 @@ func (r *Resolver) ipExchange(ctx context.Context, m *D.Msg) (msg *D.Msg, err er
|
|||
return
|
||||
}
|
||||
|
||||
func (r *Resolver) resolveIP(host string, dnsType uint16) (ip net.IP, err error) {
|
||||
ip = net.ParseIP(host)
|
||||
if ip != nil {
|
||||
isIPv4 := ip.To4() != nil
|
||||
func (r *Resolver) resolveIP(host string, dnsType uint16) (ip netip.Addr, err error) {
|
||||
ip, err = netip.ParseAddr(host)
|
||||
if err == nil {
|
||||
isIPv4 := ip.Is4()
|
||||
if dnsType == D.TypeAAAA && !isIPv4 {
|
||||
return ip, nil
|
||||
} else if dnsType == D.TypeA && isIPv4 {
|
||||
return ip, nil
|
||||
} else {
|
||||
return nil, resolver.ErrIPVersion
|
||||
return netip.Addr{}, resolver.ErrIPVersion
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,13 +272,13 @@ func (r *Resolver) resolveIP(host string, dnsType uint16) (ip net.IP, err error)
|
|||
|
||||
msg, err := r.Exchange(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return netip.Addr{}, err
|
||||
}
|
||||
|
||||
ips := msgToIP(msg)
|
||||
ipLength := len(ips)
|
||||
if ipLength == 0 {
|
||||
return nil, resolver.ErrIPNotFound
|
||||
return netip.Addr{}, resolver.ErrIPNotFound
|
||||
}
|
||||
|
||||
ip = ips[rand.Intn(ipLength)]
|
||||
|
@ -318,7 +317,7 @@ type NameServer struct {
|
|||
type FallbackFilter struct {
|
||||
GeoIP bool
|
||||
GeoIPCode string
|
||||
IPCIDR []*net.IPNet
|
||||
IPCIDR []*netip.Prefix
|
||||
Domain []string
|
||||
GeoSite []*router.DomainMatcher
|
||||
}
|
||||
|
@ -359,7 +358,7 @@ func NewResolver(config Config) *Resolver {
|
|||
if len(config.Policy) != 0 {
|
||||
r.policy = trie.New[*Policy]()
|
||||
for domain, nameserver := range config.Policy {
|
||||
r.policy.Insert(domain, NewPolicy(transform([]NameServer{nameserver}, defaultResolver)))
|
||||
_ = r.policy.Insert(domain, NewPolicy(transform([]NameServer{nameserver}, defaultResolver)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
14
dns/util.go
14
dns/util.go
|
@ -5,9 +5,11 @@ import (
|
|||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/common/cache"
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
|
@ -99,15 +101,15 @@ func handleMsgWithEmptyAnswer(r *D.Msg) *D.Msg {
|
|||
return msg
|
||||
}
|
||||
|
||||
func msgToIP(msg *D.Msg) []net.IP {
|
||||
ips := []net.IP{}
|
||||
func msgToIP(msg *D.Msg) []netip.Addr {
|
||||
ips := []netip.Addr{}
|
||||
|
||||
for _, answer := range msg.Answer {
|
||||
switch ans := answer.(type) {
|
||||
case *D.AAAA:
|
||||
ips = append(ips, ans.AAAA)
|
||||
ips = append(ips, nnip.IpToAddr(ans.AAAA))
|
||||
case *D.A:
|
||||
ips = append(ips, ans.A)
|
||||
ips = append(ips, nnip.IpToAddr(ans.A))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +134,7 @@ func (wpc *wrapPacketConn) RemoteAddr() net.Addr {
|
|||
return wpc.rAddr
|
||||
}
|
||||
|
||||
func dialContextWithProxyAdapter(ctx context.Context, adapterName string, network string, dstIP net.IP, port string, opts ...dialer.Option) (net.Conn, error) {
|
||||
func dialContextWithProxyAdapter(ctx context.Context, adapterName string, network string, dstIP netip.Addr, port string, opts ...dialer.Option) (net.Conn, error) {
|
||||
adapter, ok := tunnel.Proxies()[adapterName]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("proxy adapter [%s] not found", adapterName)
|
||||
|
@ -147,7 +149,7 @@ func dialContextWithProxyAdapter(ctx context.Context, adapterName string, networ
|
|||
}
|
||||
|
||||
addrType := C.AtypIPv4
|
||||
if dstIP.To4() == nil {
|
||||
if dstIP.Is6() {
|
||||
addrType = C.AtypIPv6
|
||||
}
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref
|
|||
lAddr := conn.LocalAddr().(*net.TCPAddr)
|
||||
rAddr := conn.RemoteAddr().(*net.TCPAddr)
|
||||
|
||||
lAddrPort := netip.AddrPortFrom(nnip.IpToAddr(lAddr.IP), uint16(lAddr.Port))
|
||||
rAddrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), uint16(rAddr.Port))
|
||||
|
||||
if rAddrPort.Addr().IsLoopback() {
|
||||
|
@ -135,8 +136,8 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref
|
|||
metadata := &C.Metadata{
|
||||
NetWork: C.TCP,
|
||||
Type: C.TUN,
|
||||
SrcIP: lAddr.IP,
|
||||
DstIP: rAddr.IP,
|
||||
SrcIP: lAddrPort.Addr(),
|
||||
DstIP: rAddrPort.Addr(),
|
||||
SrcPort: strconv.Itoa(lAddr.Port),
|
||||
DstPort: strconv.Itoa(rAddr.Port),
|
||||
AddrType: C.AtypIPv4,
|
||||
|
|
|
@ -50,7 +50,7 @@ func New(tunConf *config.Tun, dnsConf *config.DNS, tcpIn chan<- C.ConnContext, u
|
|||
tunAddress = netip.MustParsePrefix("198.18.0.1/16")
|
||||
}
|
||||
|
||||
process.AppendLocalIPs(tunAddress.Masked().Addr().Next().AsSlice())
|
||||
process.AppendLocalIPs(tunAddress.Masked().Addr().Next())
|
||||
|
||||
// open tun device
|
||||
tunDevice, err = parseDevice(devName, uint32(mtu))
|
||||
|
|
|
@ -2,7 +2,7 @@ package common
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
|
@ -54,17 +54,17 @@ func FindNetwork(params []string) C.NetWork {
|
|||
return C.ALLNet
|
||||
}
|
||||
|
||||
func FindSourceIPs(params []string) []*net.IPNet {
|
||||
var ips []*net.IPNet
|
||||
func FindSourceIPs(params []string) []*netip.Prefix {
|
||||
var ips []*netip.Prefix
|
||||
for _, p := range params {
|
||||
if p == noResolve || len(p) < 7 {
|
||||
continue
|
||||
}
|
||||
_, ipnet, err := net.ParseCIDR(p)
|
||||
ipnet, err := netip.ParsePrefix(p)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
ips = append(ips, ipnet)
|
||||
ips = append(ips, &ipnet)
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
|
|
|
@ -26,7 +26,7 @@ func (g *GEOIP) RuleType() C.RuleType {
|
|||
|
||||
func (g *GEOIP) Match(metadata *C.Metadata) bool {
|
||||
ip := metadata.DstIP
|
||||
if ip == nil {
|
||||
if !ip.IsValid() {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -39,10 +39,10 @@ func (g *GEOIP) Match(metadata *C.Metadata) bool {
|
|||
resolver.IsFakeBroadcastIP(ip)
|
||||
}
|
||||
if !C.GeodataMode {
|
||||
record, _ := mmdb.Instance().Country(ip)
|
||||
record, _ := mmdb.Instance().Country(ip.AsSlice())
|
||||
return strings.EqualFold(record.Country.IsoCode, g.country)
|
||||
}
|
||||
return g.geoIPMatcher.Match(ip)
|
||||
return g.geoIPMatcher.Match(ip.AsSlice())
|
||||
}
|
||||
|
||||
func (g *GEOIP) Adapter() string {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
)
|
||||
|
@ -22,7 +22,7 @@ func WithIPCIDRNoResolve(noResolve bool) IPCIDROption {
|
|||
|
||||
type IPCIDR struct {
|
||||
*Base
|
||||
ipnet *net.IPNet
|
||||
ipnet *netip.Prefix
|
||||
adapter string
|
||||
isSourceIP bool
|
||||
noResolveIP bool
|
||||
|
@ -40,7 +40,7 @@ func (i *IPCIDR) Match(metadata *C.Metadata) bool {
|
|||
if i.isSourceIP {
|
||||
ip = metadata.SrcIP
|
||||
}
|
||||
return ip != nil && i.ipnet.Contains(ip)
|
||||
return ip.IsValid() && i.ipnet.Contains(ip)
|
||||
}
|
||||
|
||||
func (i *IPCIDR) Adapter() string {
|
||||
|
@ -56,14 +56,14 @@ func (i *IPCIDR) ShouldResolveIP() bool {
|
|||
}
|
||||
|
||||
func NewIPCIDR(s string, adapter string, opts ...IPCIDROption) (*IPCIDR, error) {
|
||||
_, ipnet, err := net.ParseCIDR(s)
|
||||
ipnet, err := netip.ParsePrefix(s)
|
||||
if err != nil {
|
||||
return nil, errPayload
|
||||
}
|
||||
|
||||
ipcidr := &IPCIDR{
|
||||
Base: &Base{},
|
||||
ipnet: ipnet,
|
||||
ipnet: &ipnet,
|
||||
adapter: adapter,
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ type ipcidrStrategy struct {
|
|||
}
|
||||
|
||||
func (i *ipcidrStrategy) Match(metadata *C.Metadata) bool {
|
||||
return i.trie != nil && i.trie.IsContain(metadata.DstIP)
|
||||
return i.trie != nil && i.trie.IsContain(metadata.DstIP.AsSlice())
|
||||
}
|
||||
|
||||
func (i *ipcidrStrategy) Count() int {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
|
||||
"github.com/Dreamacro/clash/component/auth"
|
||||
|
@ -40,6 +41,8 @@ var (
|
|||
ErrRequestUnknownCode = errors.New("request failed with unknown code")
|
||||
)
|
||||
|
||||
var subnet = netip.PrefixFrom(netip.IPv4Unspecified(), 24)
|
||||
|
||||
func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr string, command Command, err error) {
|
||||
var req [8]byte
|
||||
if _, err = io.ReadFull(rw, req[:]); err != nil {
|
||||
|
@ -57,7 +60,7 @@ func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr s
|
|||
}
|
||||
|
||||
var (
|
||||
dstIP = req[4:8] // [4]byte
|
||||
dstIP = netip.AddrFrom4(*(*[4]byte)(req[4:8])) // [4]byte
|
||||
dstPort = req[2:4] // [2]byte
|
||||
)
|
||||
|
||||
|
@ -83,7 +86,7 @@ func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr s
|
|||
if host != "" {
|
||||
addr = net.JoinHostPort(host, port)
|
||||
} else {
|
||||
addr = net.JoinHostPort(net.IP(dstIP).String(), port)
|
||||
addr = net.JoinHostPort(dstIP.String(), port)
|
||||
}
|
||||
|
||||
// SOCKS4 only support USERID auth.
|
||||
|
@ -97,7 +100,7 @@ func ServerHandshake(rw io.ReadWriter, authenticator auth.Authenticator) (addr s
|
|||
var reply [8]byte
|
||||
reply[0] = 0x00 // reply code
|
||||
reply[1] = code // result code
|
||||
copy(reply[4:8], dstIP)
|
||||
copy(reply[4:8], dstIP.AsSlice())
|
||||
copy(reply[2:4], dstPort)
|
||||
|
||||
_, wErr := rw.Write(reply[:])
|
||||
|
@ -118,20 +121,18 @@ func ClientHandshake(rw io.ReadWriter, addr string, command Command, userID stri
|
|||
return err
|
||||
}
|
||||
|
||||
ip := net.ParseIP(host)
|
||||
if ip == nil /* HOST */ {
|
||||
ip = net.IPv4(0, 0, 0, 1).To4()
|
||||
} else if ip.To4() == nil /* IPv6 */ {
|
||||
dstIP, err := netip.ParseAddr(host)
|
||||
if err != nil /* HOST */ {
|
||||
dstIP = netip.AddrFrom4([4]byte{0, 0, 0, 1})
|
||||
} else if dstIP.Is6() /* IPv6 */ {
|
||||
return errIPv6NotSupported
|
||||
}
|
||||
|
||||
dstIP := ip.To4()
|
||||
|
||||
req := &bytes.Buffer{}
|
||||
req.WriteByte(Version)
|
||||
req.WriteByte(command)
|
||||
binary.Write(req, binary.BigEndian, uint16(port))
|
||||
req.Write(dstIP)
|
||||
_ = binary.Write(req, binary.BigEndian, uint16(port))
|
||||
req.Write(dstIP.AsSlice())
|
||||
req.WriteString(userID)
|
||||
req.WriteByte(0) /* NULL */
|
||||
|
||||
|
@ -174,12 +175,7 @@ func ClientHandshake(rw io.ReadWriter, addr string, command Command, userID stri
|
|||
// Internet Assigned Numbers Authority -- such an address is inadmissible
|
||||
// as a destination IP address and thus should never occur if the client
|
||||
// can resolve the domain name.)
|
||||
func isReservedIP(ip net.IP) bool {
|
||||
subnet := net.IPNet{
|
||||
IP: net.IPv4zero,
|
||||
Mask: net.IPv4Mask(0xff, 0xff, 0xff, 0x00),
|
||||
}
|
||||
|
||||
func isReservedIP(ip netip.Addr) bool {
|
||||
return !ip.IsUnspecified() && subnet.Contains(ip)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
P "github.com/Dreamacro/clash/component/process"
|
||||
"net"
|
||||
"net/netip"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
@ -131,15 +132,15 @@ func process() {
|
|||
}
|
||||
|
||||
func needLookupIP(metadata *C.Metadata) bool {
|
||||
return resolver.MappingEnabled() && metadata.Host == "" && metadata.DstIP != nil
|
||||
return resolver.MappingEnabled() && metadata.Host == "" && metadata.DstIP.IsValid()
|
||||
}
|
||||
|
||||
func preHandleMetadata(metadata *C.Metadata) error {
|
||||
// handle IP string on host
|
||||
if ip := net.ParseIP(metadata.Host); ip != nil {
|
||||
if ip, err := netip.ParseAddr(metadata.Host); err == nil {
|
||||
metadata.DstIP = ip
|
||||
metadata.Host = ""
|
||||
if ip.To4() != nil {
|
||||
if ip.Is4() {
|
||||
metadata.AddrType = C.AtypIPv4
|
||||
} else {
|
||||
metadata.AddrType = C.AtypIPv6
|
||||
|
@ -154,11 +155,11 @@ func preHandleMetadata(metadata *C.Metadata) error {
|
|||
metadata.AddrType = C.AtypDomainName
|
||||
metadata.DNSMode = C.DNSMapping
|
||||
if resolver.FakeIPEnabled() {
|
||||
metadata.DstIP = nil
|
||||
metadata.DstIP = netip.Addr{}
|
||||
metadata.DNSMode = C.DNSFakeIP
|
||||
} else if node := resolver.DefaultHosts.Search(host); node != nil {
|
||||
// redir-host should lookup the hosts
|
||||
metadata.DstIP = node.Data.AsSlice()
|
||||
metadata.DstIP = node.Data
|
||||
}
|
||||
} else if resolver.IsFakeIP(metadata.DstIP) {
|
||||
return fmt.Errorf("fake DNS record %s missing", metadata.DstIP)
|
||||
|
@ -351,7 +352,7 @@ func handleTCPConn(connCtx C.ConnContext) {
|
|||
}
|
||||
|
||||
func shouldResolveIP(rule C.Rule, metadata *C.Metadata) bool {
|
||||
return rule.ShouldResolveIP() && metadata.Host != "" && metadata.DstIP == nil
|
||||
return rule.ShouldResolveIP() && metadata.Host != "" && !metadata.DstIP.IsValid()
|
||||
}
|
||||
|
||||
func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
|
||||
|
@ -360,7 +361,7 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
|
|||
var resolved bool
|
||||
|
||||
if node := resolver.DefaultHosts.Search(metadata.Host); node != nil {
|
||||
metadata.DstIP = node.Data.AsSlice()
|
||||
metadata.DstIP = node.Data
|
||||
resolved = true
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue