Skip to content

Commit 69600b7

Browse files
authored
feat: add --check flag for dns (#27)
* perf: add wg for dns list check * feat(): add --check flag for dns * fix(): check with url issue in dns, speed print * fix(): check error exist when I use CheckAndCacheDNS() * fix(): issue in CheckAndCacheDNS() * fix(): issue in goroutine CheckAndCacheDNS()
1 parent fa45df1 commit 69600b7

File tree

5 files changed

+216
-66
lines changed

5 files changed

+216
-66
lines changed

internal/check/function.go

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
package check
22

33
import (
4-
"context"
54
"fmt"
6-
"net"
75
"net/http"
86
"net/url"
9-
"os"
107
"regexp"
118
"strconv"
129
"strings"
@@ -16,27 +13,6 @@ import (
1613
"github.com/urfave/cli/v2"
1714
)
1815

19-
func ChangeDNS(dns string) *http.Client {
20-
dialer := &net.Dialer{}
21-
customResolver := &net.Resolver{
22-
PreferGo: true,
23-
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
24-
dnsServer := fmt.Sprintf("%s:53", dns)
25-
return dialer.DialContext(ctx, "udp", dnsServer)
26-
},
27-
}
28-
customDialer := &net.Dialer{
29-
Resolver: customResolver,
30-
}
31-
transport := &http.Transport{
32-
DialContext: customDialer.DialContext,
33-
}
34-
client := &http.Client{
35-
Transport: transport,
36-
}
37-
return client
38-
}
39-
4016
func CheckWithDNS(c *cli.Context) error {
4117
url := c.Args().First()
4218
url = ensureHTTPS(url)
@@ -48,14 +24,14 @@ func CheckWithDNS(c *cli.Context) error {
4824
fmt.Printf("| %-18s | %-10s |\n", "DNS Server", "Status")
4925
fmt.Println("+--------------------+------------+")
5026

51-
dnsList, err := ReadDNSFromFile(common.DNS_CONFIG_FILE)
27+
dnsList, err := common.ReadDNSFromFile(common.DNS_CONFIG_FILE)
5228
if err != nil {
5329
err = common.DownloadConfigFile(common.DNS_CONFIG_URL, common.DNS_CONFIG_FILE)
5430
if err != nil {
5531
return err
5632
}
5733

58-
dnsList, err = ReadDNSFromFile(common.DNS_CONFIG_FILE)
34+
dnsList, err = common.ReadDNSFromFile(common.DNS_CONFIG_FILE)
5935

6036
if err != nil {
6137
fmt.Println(err)
@@ -68,7 +44,7 @@ func CheckWithDNS(c *cli.Context) error {
6844
wg.Add(1)
6945
go func(dns string) {
7046
defer wg.Done()
71-
client := ChangeDNS(dns)
47+
client := common.ChangeDNS(dns)
7248
resp, err := client.Get(url)
7349
if err != nil {
7450
return
@@ -97,20 +73,6 @@ func CheckWithDNS(c *cli.Context) error {
9773
return nil
9874
}
9975

100-
func ReadDNSFromFile(filename string) ([]string, error) {
101-
homeDir := os.Getenv("HOME")
102-
if homeDir == "" {
103-
fmt.Println("HOME environment variable not set")
104-
os.Exit(1)
105-
}
106-
filename = homeDir + "/" + filename
107-
data, err := os.ReadFile(filename)
108-
if err != nil {
109-
return nil, err
110-
}
111-
dnsServers := strings.Fields(string(data))
112-
return dnsServers, nil
113-
}
11476
func DomainValidator(domain string) bool {
11577
domainRegex := `^(http[s]?:\/\/)?([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}).*?$`
11678
match, _ := regexp.MatchString(domainRegex, domain)

internal/common/function.go

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package common
22

33
import (
4+
"context"
45
"fmt"
56
"io"
7+
"net"
68
"net/http"
79
"os"
810
"path/filepath"
11+
"strings"
912
)
1013

1114
const (
@@ -21,10 +24,11 @@ const (
2124
White = "\033[97m"
2225

2326
// DNS config
24-
DNS_CONFIG_FILE = ".config/403unlocker/dns.conf"
25-
DOCKER_CONFIG_FILE = ".config/403unlocker/dockerRegistry.conf"
26-
DNS_CONFIG_URL = "https://raw.githubusercontent.com/403unlocker/403Unlocker-cli/refs/heads/main/config/dns.conf"
27-
DOCKER_CONFIG_URL = "https://raw.githubusercontent.com/403unlocker/403Unlocker-cli/refs/heads/main/config/dockerRegistry.conf"
27+
DNS_CONFIG_FILE = ".config/403unlocker/dns.conf"
28+
CHECKED_DNS_CONFIG_FILE = ".config/403unlocker/checked_dns.conf"
29+
DOCKER_CONFIG_FILE = ".config/403unlocker/dockerRegistry.conf"
30+
DNS_CONFIG_URL = "https://raw.githubusercontent.com/403unlocker/403Unlocker-cli/refs/heads/main/config/dns.conf"
31+
DOCKER_CONFIG_URL = "https://raw.githubusercontent.com/403unlocker/403Unlocker-cli/refs/heads/main/config/dockerRegistry.conf"
2832
)
2933

3034
// FormatDataSize converts the size in bytes to a human-readable string in KB, MB, or GB.
@@ -94,3 +98,69 @@ func DownloadConfigFile(url, path string) error {
9498

9599
return nil
96100
}
101+
102+
func WriteDNSToFile(filename string, dnsList []string) error {
103+
homeDir := os.Getenv("HOME")
104+
if homeDir == "" {
105+
fmt.Println("HOME environment variable not set")
106+
os.Exit(1)
107+
}
108+
109+
filename = homeDir + "/" + filename
110+
111+
_, err := os.Stat(filename)
112+
if os.IsNotExist(err) {
113+
file, err := os.Create(filename)
114+
if err != nil {
115+
fmt.Printf("Error creating file %s: %v\n", filename, err)
116+
return err
117+
}
118+
file.Close()
119+
}
120+
121+
content := strings.Join(dnsList, " ")
122+
123+
err = os.WriteFile(filename, []byte(content), 0644)
124+
if err != nil {
125+
fmt.Printf("Error writing to file %s: %v\n", filename, err)
126+
return err
127+
}
128+
129+
return nil
130+
}
131+
132+
func ReadDNSFromFile(filename string) ([]string, error) {
133+
homeDir := os.Getenv("HOME")
134+
if homeDir == "" {
135+
fmt.Println("HOME environment variable not set")
136+
os.Exit(1)
137+
}
138+
filename = homeDir + "/" + filename
139+
data, err := os.ReadFile(filename)
140+
if err != nil {
141+
return nil, err
142+
}
143+
dnsServers := strings.Fields(string(data))
144+
return dnsServers, nil
145+
}
146+
147+
func ChangeDNS(dns string) *http.Client {
148+
dialer := &net.Dialer{}
149+
customResolver := &net.Resolver{
150+
PreferGo: true,
151+
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
152+
dnsServer := fmt.Sprintf("%s:53", dns)
153+
return dialer.DialContext(ctx, "udp", dnsServer)
154+
},
155+
}
156+
customDialer := &net.Dialer{
157+
Resolver: customResolver,
158+
}
159+
transport := &http.Transport{
160+
DialContext: customDialer.DialContext,
161+
}
162+
client := &http.Client{
163+
Transport: transport,
164+
}
165+
return client
166+
}

internal/dns/function.go

Lines changed: 116 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ package dns
33
import (
44
"context"
55
"fmt"
6+
"net/http"
67
"net/url"
78
"os"
9+
"strconv"
10+
"strings"
11+
"sync"
812
"time"
913

1014
"github.com/cavaliergopher/grab/v3"
11-
"github.com/salehborhani/403Unlocker-cli/internal/check"
1215
"github.com/salehborhani/403Unlocker-cli/internal/common"
1316
"github.com/urfave/cli/v2"
1417
)
@@ -29,25 +32,127 @@ func URLValidator(URL string) bool {
2932
}
3033
return true
3134
}
32-
func CheckWithURL(c *cli.Context) error {
33-
fileToDownload := c.Args().First()
34-
timeout := c.Int("timeout")
3535

36-
dnsList, err := check.ReadDNSFromFile(common.DNS_CONFIG_FILE)
36+
func CheckAndCacheDNS(url string) error {
37+
cacheFile := common.CHECKED_DNS_CONFIG_FILE
38+
39+
dnsList, err := common.ReadDNSFromFile(common.DNS_CONFIG_FILE)
3740
if err != nil {
3841
err = common.DownloadConfigFile(common.DNS_CONFIG_URL, common.DNS_CONFIG_FILE)
3942
if err != nil {
43+
fmt.Println("Error downloading DNS config file:", err)
4044
return err
4145
}
42-
dnsList, err = check.ReadDNSFromFile(common.DNS_CONFIG_FILE)
4346

47+
dnsList, err = common.ReadDNSFromFile(common.DNS_CONFIG_FILE)
4448
if err != nil {
45-
fmt.Println("Error reading DNS list:", err)
49+
fmt.Println("Error reading DNS list from file:", err)
4650
return err
4751
}
4852
}
4953

54+
fmt.Println("\n+--------------------+------------+")
55+
fmt.Printf("| %-18s | %-10s |\n", "DNS Server", "Status")
56+
fmt.Println("+--------------------+------------+")
57+
58+
var validDNSList []string
59+
var wg sync.WaitGroup
60+
var mu sync.Mutex
61+
62+
for _, dns := range dnsList {
63+
wg.Add(1)
64+
go func(dns string) {
65+
defer wg.Done()
66+
67+
// Change DNS for the HTTP client
68+
client := common.ChangeDNS(dns)
69+
70+
// Perform the GET request
71+
resp, err := client.Get(url)
72+
if err != nil {
73+
fmt.Printf("| %-18s | %s%-10s%s |\n", dns, common.Red, "Error", common.Reset)
74+
return
75+
}
76+
defer resp.Body.Close()
77+
78+
// Parse the status code
79+
codeParts := strings.Split(resp.Status, " ")
80+
if len(codeParts) < 2 {
81+
fmt.Printf("| %-18s | %s%-10s%s |\n", dns, common.Red, "Invalid", common.Reset)
82+
return
83+
}
84+
85+
statusCode, err := strconv.Atoi(codeParts[0])
86+
if err != nil {
87+
fmt.Printf("| %-18s | %s%-10s%s |\n", dns, common.Red, "Error", common.Reset)
88+
return
89+
}
90+
91+
// Output the status with appropriate color
92+
statusText := codeParts[1]
93+
94+
if statusCode == http.StatusOK {
95+
mu.Lock()
96+
validDNSList = append(validDNSList, dns)
97+
mu.Unlock()
98+
fmt.Printf("| %-18s | %s%-10s%s |\n", dns, common.Green, statusText, common.Reset)
99+
} else {
100+
fmt.Printf("| %-18s | %s%-10s%s |\n", dns, common.Red, statusText, common.Reset)
101+
}
102+
}(dns)
103+
}
104+
105+
wg.Wait()
106+
107+
fmt.Println("+--------------------+------------+")
108+
109+
fmt.Println("Valid DNS List: ", validDNSList)
110+
111+
if len(validDNSList) > 0 {
112+
err = common.WriteDNSToFile(cacheFile, validDNSList)
113+
if err != nil {
114+
fmt.Println("Error writing to cached DNS file:", err)
115+
return err
116+
}
117+
fmt.Printf("Cached %d valid DNS servers to %s\n", len(validDNSList), cacheFile)
118+
} else {
119+
fmt.Println("No valid DNS servers found to cache.")
120+
}
121+
122+
return nil
123+
}
124+
125+
func CheckWithURL(c *cli.Context) error {
126+
fileToDownload := c.Args().First()
127+
128+
var dnsFile string
129+
if c.Bool("check") {
130+
err := CheckAndCacheDNS(fileToDownload)
131+
if err != nil {
132+
return err
133+
}
134+
dnsFile = common.CHECKED_DNS_CONFIG_FILE
135+
} else {
136+
dnsFile = common.DNS_CONFIG_FILE
137+
}
138+
139+
// Read the DNS list from the determined file
140+
dnsList, err := common.ReadDNSFromFile(dnsFile)
141+
if err != nil {
142+
// Fallback to download and read from the original DNS file
143+
err = common.DownloadConfigFile(common.DNS_CONFIG_URL, common.DNS_CONFIG_FILE)
144+
if err != nil {
145+
return fmt.Errorf("error downloading DNS config file: %w", err)
146+
}
147+
dnsList, err = common.ReadDNSFromFile(common.DNS_CONFIG_FILE)
148+
if err != nil {
149+
return fmt.Errorf("error reading DNS list from file: %w", err)
150+
}
151+
}
152+
50153
dnsSizeMap := make(map[string]int64)
154+
155+
timeout := c.Int("timeout")
51156
fmt.Printf("\nTimeout: %d seconds\n", timeout)
52157
fmt.Printf("URL: %s\n\n", fileToDownload)
53158

@@ -57,11 +162,12 @@ func CheckWithURL(c *cli.Context) error {
57162
fmt.Println("+--------------------+----------------+")
58163

59164
tempDir := time.Now().UnixMilli()
165+
var wg sync.WaitGroup
60166
for _, dns := range dnsList {
61167
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
62168
defer cancel()
63169

64-
clientWithCustomDNS := check.ChangeDNS(dns)
170+
clientWithCustomDNS := common.ChangeDNS(dns)
65171
client := grab.NewClient()
66172
client.HTTPClient = clientWithCustomDNS
67173

@@ -80,8 +186,10 @@ func CheckWithURL(c *cli.Context) error {
80186
} else {
81187
fmt.Printf("| %-18s | %-14s |\n", dns, speed+"/s")
82188
}
189+
83190
}
84191

192+
wg.Wait()
85193
// Print table footer
86194
fmt.Println("+--------------------+----------------+")
87195

internal/docker/function.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
"github.com/google/go-containerregistry/pkg/name"
1818
"github.com/google/go-containerregistry/pkg/v1/remote"
1919
"github.com/google/go-containerregistry/pkg/v1/tarball"
20-
"github.com/salehborhani/403Unlocker-cli/internal/check"
2120
"github.com/salehborhani/403Unlocker-cli/internal/common"
2221
"github.com/urfave/cli/v2"
2322
)
@@ -112,14 +111,14 @@ func CheckWithDockerImage(c *cli.Context) error {
112111
return fmt.Errorf("image name cannot be empty")
113112
}
114113

115-
registryList, err := check.ReadDNSFromFile(common.DOCKER_CONFIG_FILE)
114+
registryList, err := common.ReadDNSFromFile(common.DOCKER_CONFIG_FILE)
116115
if err != nil {
117116
err = common.DownloadConfigFile(common.DOCKER_CONFIG_URL, common.DOCKER_CONFIG_FILE)
118117
if err != nil {
119118
return err
120119
}
121120

122-
registryList, err = check.ReadDNSFromFile(common.DOCKER_CONFIG_FILE)
121+
registryList, err = common.ReadDNSFromFile(common.DOCKER_CONFIG_FILE)
123122
if err != nil {
124123
log.Printf("Error reading registry list: %v", err)
125124
return err

0 commit comments

Comments
 (0)