Skip to content

Commit 05d4298

Browse files
committed
feat(debug): add netcheck
add netcheck Signed-off-by: ysicing <i@ysicing.me>
1 parent 31c80b3 commit 05d4298

File tree

5 files changed

+148
-0
lines changed

5 files changed

+148
-0
lines changed

cmd/debug.go

+1
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ func newCmdDebug(f factory.Factory) *cobra.Command {
2525
debugCmd.AddCommand(debug.DownloadCommand(f))
2626
debugCmd.AddCommand(debug.CleanCacheCommand(f))
2727
debugCmd.AddCommand(debug.GOpsCommand(f))
28+
debugCmd.AddCommand(debug.NetCheckCommand(f))
2829
return debugCmd
2930
}

cmd/debug/netcheck.go

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) 2023 ysicing(ysicing.me, ysicing@ysicing.cloud) All rights reserved.
2+
// Use of this source code is covered by the following dual licenses:
3+
// (1) Y PUBLIC LICENSE 1.0 (YPL 1.0)
4+
// (2) Affero General Public License 3.0 (AGPL 3.0)
5+
// License that can be found in the LICENSE file.
6+
7+
package debug
8+
9+
import (
10+
"github.com/spf13/cobra"
11+
"github.com/ysicing/tiga/pkg/factory"
12+
"github.com/ysicing/tiga/pkg/util/netutil"
13+
)
14+
15+
func NetCheckCommand(f factory.Factory) *cobra.Command {
16+
logpkg := f.GetLog()
17+
cmd := &cobra.Command{
18+
Use: "netcheck",
19+
Short: "netcheck",
20+
Run: func(cmd *cobra.Command, args []string) {
21+
if gw, err := netutil.CheckDefaultRoute(); err == nil {
22+
logpkg.Donef("default route %s reachable via icmp", gw.String())
23+
} else {
24+
logpkg.Warnf("default route %s unreachable via icmp", gw.String())
25+
}
26+
if ns, err := netutil.GetDefaultNameserver(); err == nil {
27+
a := ""
28+
29+
if !netutil.CheckReachabilityWithICMP(ns) {
30+
a = "un"
31+
}
32+
if err := netutil.CheckNameserverAvailability(ns + ":53"); err != nil {
33+
logpkg.Warnf("Default nameserver: %s (ICMP %s reachable, DNS unreachable: %s)", ns, a, err)
34+
} else {
35+
logpkg.Donef("Default nameserver: %s (ICMP %s reachable, DNS reachable)", ns, a)
36+
}
37+
} else {
38+
logpkg.Warnf("failed to reading default nameserver from system: %s", err)
39+
}
40+
},
41+
}
42+
return cmd
43+
}

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@ require (
1010
github.com/cockroachdb/errors v1.9.1
1111
github.com/containerd/continuity v0.3.0
1212
github.com/ergoapi/util v0.4.0
13+
github.com/go-ping/ping v1.1.0
1314
github.com/google/gops v0.3.27
1415
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf
16+
github.com/jackpal/gateway v1.0.10
1517
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213
1618
github.com/loft-sh/utils v0.0.18
1719
github.com/mattn/go-isatty v0.0.18
1820
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
21+
github.com/miekg/dns v1.1.54
1922
github.com/moby/term v0.5.0
2023
github.com/morikuni/aec v1.0.0
2124
github.com/muesli/mango-cobra v1.2.0

go.sum

+9
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTr
114114
github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
115115
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
116116
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
117+
github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
118+
github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
117119
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
118120
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
119121
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
@@ -172,6 +174,7 @@ github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3 h1:2XF1Vzq06X+inNqgJ9
172174
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
173175
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
174176
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
177+
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
175178
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
176179
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
177180
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -198,6 +201,8 @@ github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/
198201
github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
199202
github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
200203
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
204+
github.com/jackpal/gateway v1.0.10 h1:7g3fDo4Cd3RnTu6PzAfw6poO4Y81uNxrxFQFsBFSzJM=
205+
github.com/jackpal/gateway v1.0.10/go.mod h1:+uPBgIllrbkwYCAoDkGSZbjvpre/bGYAFCYIcrH+LHs=
201206
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
202207
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
203208
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -263,6 +268,8 @@ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyex
263268
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
264269
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
265270
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
271+
github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI=
272+
github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
266273
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
267274
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
268275
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
@@ -448,6 +455,7 @@ golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLL
448455
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
449456
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
450457
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
458+
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
451459
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
452460
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
453461
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
@@ -479,6 +487,7 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
479487
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
480488
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
481489
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
490+
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
482491
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
483492
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
484493
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

pkg/util/netutil/netutil.go

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright (c) 2023 ysicing(ysicing.me, ysicing@ysicing.cloud) All rights reserved.
2+
// Use of this source code is covered by the following dual licenses:
3+
// (1) Y PUBLIC LICENSE 1.0 (YPL 1.0)
4+
// (2) Affero General Public License 3.0 (AGPL 3.0)
5+
// License that can be found in the LICENSE file.
6+
7+
package netutil
8+
9+
import (
10+
"fmt"
11+
"github.com/cockroachdb/errors"
12+
"github.com/go-ping/ping"
13+
"github.com/jackpal/gateway"
14+
"github.com/miekg/dns"
15+
"io/fs"
16+
"net"
17+
"os"
18+
"regexp"
19+
"time"
20+
)
21+
22+
// CheckDefaultRoute checks if the default route is reachable
23+
func CheckDefaultRoute() (net.IP, error) {
24+
// check default gateway
25+
gw, err := gateway.DiscoverGateway()
26+
27+
if err != nil {
28+
return nil, fmt.Errorf("error reading default route: %s", err)
29+
}
30+
31+
if CheckReachabilityWithICMP(gw.String()) {
32+
return gw, nil
33+
}
34+
35+
return gw, fmt.Errorf("default route is unreachable")
36+
}
37+
38+
// CheckReachabilityWithICMP checks if a host is reachable using ICMP
39+
func CheckReachabilityWithICMP(host string) bool {
40+
pinger, err := ping.NewPinger(host)
41+
if err != nil {
42+
return false
43+
}
44+
45+
pinger.Count = 3
46+
pinger.Debug = true
47+
pinger.Interval = 200 * time.Millisecond
48+
pinger.Timeout = 3 * time.Second
49+
50+
err = pinger.Run()
51+
52+
if err != nil {
53+
return false
54+
}
55+
56+
stats := pinger.Statistics()
57+
58+
return stats.PacketsRecv != 0
59+
}
60+
61+
// GetDefaultNameserver returns the default nameserver
62+
func GetDefaultNameserver() (string, error) {
63+
// get default ns from /etc/resolv.conf
64+
byteString, err := fs.ReadFile(os.DirFS("/etc"), "resolv.conf")
65+
if err != nil {
66+
return "", err
67+
}
68+
s := string(byteString)
69+
re := regexp.MustCompile(`(?m)^nameserver( *|\t*)(.*?)$`)
70+
match := re.FindStringSubmatch(s)
71+
72+
if len(match) < 2 {
73+
return "", errors.New("nameserver not found")
74+
}
75+
return match[2], nil
76+
}
77+
78+
// CheckNameserverAvailability checks if a nameserver is reachable using DNS
79+
func CheckNameserverAvailability(s string) error {
80+
c := new(dns.Client)
81+
c.Dialer = &net.Dialer{
82+
Timeout: 3 * time.Second,
83+
}
84+
m := new(dns.Msg)
85+
m.SetQuestion("apple.com.", dns.TypeA)
86+
_, _, err := c.Exchange(m, s)
87+
88+
if err != nil {
89+
return err
90+
}
91+
return nil
92+
}

0 commit comments

Comments
 (0)