package netutil import ( "context" "log" "net" "net/http" "net/url" "strings" "time" "github.com/gobwas/ws" "github.com/net-byte/vtun/common/config" ) func ConnectServer(config config.Config) net.Conn { net.DefaultResolver = &net.Resolver{ PreferGo: true, Dial: func(ctx context.Context, network, _ string) (net.Conn, error) { var dialer net.Dialer return dialer.DialContext(ctx, network, config.DNS) }, } scheme := "ws" if config.Protocol == "wss" { scheme = "wss" } u := url.URL{Scheme: scheme, Host: config.ServerAddr, Path: config.WebSocketPath} header := make(http.Header) header.Set("user-agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36") header.Set("key", config.Key) dialer := ws.Dialer{ Header: ws.HandshakeHeaderHTTP(header), Timeout: time.Duration(config.Timeout) * time.Second, } c, _, _, err := dialer.Dial(context.Background(), u.String()) if err != nil { log.Printf("[client] failed to dial websocket %s %v", u.String(), err) return nil } return c } func GetPhysicalInterface() (name string, gateway string, network string) { ifaces := getAllPhysicalInterfaces() if len(ifaces) == 0 { return "", "", "" } netAddrs, _ := ifaces[0].Addrs() for _, addr := range netAddrs { ip, ok := addr.(*net.IPNet) if ok && ip.IP.To4() != nil && !ip.IP.IsLoopback() { ipNet := ip.IP.To4().Mask(ip.IP.DefaultMask()).To4() network = strings.Join([]string{ipNet.String(), strings.Split(ip.String(), "/")[1]}, "/") ipNet[3]++ gateway = ipNet.String() name = ifaces[0].Name log.Printf("physical interface %v gateway %v network %v", name, gateway, network) break } } return name, gateway, network } func getAllPhysicalInterfaces() []net.Interface { ifaces, err := net.Interfaces() if err != nil { log.Println(err) return nil } var outInterfaces []net.Interface for _, iface := range ifaces { if iface.Flags&net.FlagLoopback == 0 && iface.Flags&net.FlagUp == 1 && isPhysicalInterface(iface.Name) { netAddrs, _ := iface.Addrs() if len(netAddrs) > 0 { outInterfaces = append(outInterfaces, iface) } } } return outInterfaces } func isPhysicalInterface(addr string) bool { prefixArray := []string{"ens", "enp", "enx", "eno", "eth", "en0", "wlan", "wlp", "wlo", "wlx", "wifi0", "lan0"} for _, pref := range prefixArray { if strings.HasPrefix(strings.ToLower(addr), pref) { return true } } return false } func LookupIP(domain string) string { ips, err := net.LookupIP(domain) if err != nil { log.Println(err) return "" } for _, ip := range ips { return ip.To4().String() } return "" } func IsIPv4(packet []byte) bool { return 4 == (packet[0] >> 4) } func IsIPv6(packet []byte) bool { return 6 == (packet[0] >> 4) } func GetIPv4Source(packet []byte) net.IP { return net.IPv4(packet[12], packet[13], packet[14], packet[15]) } func GetIPv4Destination(packet []byte) net.IP { return net.IPv4(packet[16], packet[17], packet[18], packet[19]) } func GetIPv6Source(packet []byte) net.IP { return net.IP(packet[8:24]) } func GetIPv6Destination(packet []byte) net.IP { return net.IP(packet[24:40]) } func GetSourceKey(packet []byte) string { key := "" if IsIPv4(packet) && len(packet) >= 20 { key = GetIPv4Source(packet).To4().String() } else if IsIPv6(packet) && len(packet) >= 40 { key = GetIPv6Source(packet).To16().String() } return key } func GetDestinationKey(packet []byte) string { key := "" if IsIPv4(packet) && len(packet) >= 20 { key = GetIPv4Destination(packet).To4().String() } else if IsIPv6(packet) && len(packet) >= 40 { key = GetIPv6Destination(packet).To16().String() } return key }