Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
G
gost
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nanahira
gost
Commits
38827782
Commit
38827782
authored
Nov 03, 2018
by
ginuerzh
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add live reloading support for bypass,resolver and hosts
parent
ca3853e8
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
302 additions
and
123 deletions
+302
-123
bypass.go
bypass.go
+82
-8
cmd/gost/bypass.txt
cmd/gost/bypass.txt
+8
-1
cmd/gost/cfg.go
cmd/gost/cfg.go
+11
-67
cmd/gost/dns.txt
cmd/gost/dns.txt
+5
-2
cmd/gost/hosts.txt
cmd/gost/hosts.txt
+4
-1
cmd/gost/main.go
cmd/gost/main.go
+4
-5
hosts.go
hosts.go
+53
-37
reload.go
reload.go
+52
-0
resolver.go
resolver.go
+83
-2
No files found.
bypass.go
View file @
38827782
package
gost
package
gost
import
(
import
(
"bufio"
"bytes"
"bytes"
"fmt"
"fmt"
"io"
"net"
"net"
"strconv"
"strconv"
"strings"
"strings"
"sync"
"time"
glob
"github.com/gobwas/glob"
glob
"github.com/gobwas/glob"
)
)
...
@@ -118,28 +122,30 @@ func (m *domainMatcher) String() string {
...
@@ -118,28 +122,30 @@ func (m *domainMatcher) String() string {
// It contains a list of matchers.
// It contains a list of matchers.
type
Bypass
struct
{
type
Bypass
struct
{
matchers
[]
Matcher
matchers
[]
Matcher
reverse
bool
reversed
bool
period
time
.
Duration
// the period for live reloading
mux
sync
.
Mutex
}
}
// NewBypass creates and initializes a new Bypass using matchers as its match rules.
// NewBypass creates and initializes a new Bypass using matchers as its match rules.
// The rules will be reversed if the reversed is true.
// The rules will be reversed if the reversed is true.
func
NewBypass
(
matchers
[]
Matcher
,
reverse
bool
)
*
Bypass
{
func
NewBypass
(
reversed
bool
,
matchers
...
Matcher
)
*
Bypass
{
return
&
Bypass
{
return
&
Bypass
{
matchers
:
matchers
,
matchers
:
matchers
,
reverse
:
reverse
,
reverse
d
:
reversed
,
}
}
}
}
// NewBypassPatterns creates and initializes a new Bypass using matcher patterns as its match rules.
// NewBypassPatterns creates and initializes a new Bypass using matcher patterns as its match rules.
// The rules will be reversed if the reverse is true.
// The rules will be reversed if the reverse is true.
func
NewBypassPatterns
(
patterns
[]
string
,
reverse
bool
)
*
Bypass
{
func
NewBypassPatterns
(
reversed
bool
,
patterns
...
string
)
*
Bypass
{
var
matchers
[]
Matcher
var
matchers
[]
Matcher
for
_
,
pattern
:=
range
patterns
{
for
_
,
pattern
:=
range
patterns
{
if
pattern
!=
""
{
if
pattern
!=
""
{
matchers
=
append
(
matchers
,
NewMatcher
(
pattern
))
matchers
=
append
(
matchers
,
NewMatcher
(
pattern
))
}
}
}
}
return
NewBypass
(
matchers
,
reverse
)
return
NewBypass
(
reversed
,
matchers
...
)
}
}
// Contains reports whether the bypass includes addr.
// Contains reports whether the bypass includes addr.
...
@@ -153,6 +159,10 @@ func (bp *Bypass) Contains(addr string) bool {
...
@@ -153,6 +159,10 @@ func (bp *Bypass) Contains(addr string) bool {
addr
=
host
addr
=
host
}
}
}
}
bp
.
mux
.
Lock
()
defer
bp
.
mux
.
Unlock
()
var
matched
bool
var
matched
bool
for
_
,
matcher
:=
range
bp
.
matchers
{
for
_
,
matcher
:=
range
bp
.
matchers
{
if
matcher
==
nil
{
if
matcher
==
nil
{
...
@@ -163,8 +173,8 @@ func (bp *Bypass) Contains(addr string) bool {
...
@@ -163,8 +173,8 @@ func (bp *Bypass) Contains(addr string) bool {
break
break
}
}
}
}
return
!
bp
.
reverse
&&
matched
||
return
!
bp
.
reverse
d
&&
matched
||
bp
.
reverse
&&
!
matched
bp
.
reverse
d
&&
!
matched
}
}
// AddMatchers appends matchers to the bypass matcher list.
// AddMatchers appends matchers to the bypass matcher list.
...
@@ -179,7 +189,71 @@ func (bp *Bypass) Matchers() []Matcher {
...
@@ -179,7 +189,71 @@ func (bp *Bypass) Matchers() []Matcher {
// Reversed reports whether the rules of the bypass are reversed.
// Reversed reports whether the rules of the bypass are reversed.
func
(
bp
*
Bypass
)
Reversed
()
bool
{
func
(
bp
*
Bypass
)
Reversed
()
bool
{
return
bp
.
reverse
return
bp
.
reversed
}
// Reload parses config from r, then live reloads the bypass.
func
(
bp
*
Bypass
)
Reload
(
r
io
.
Reader
)
error
{
var
matchers
[]
Matcher
scanner
:=
bufio
.
NewScanner
(
r
)
for
scanner
.
Scan
()
{
line
:=
scanner
.
Text
()
if
n
:=
strings
.
IndexByte
(
line
,
'#'
);
n
>=
0
{
line
=
line
[
:
n
]
}
line
=
strings
.
Replace
(
line
,
"
\t
"
,
" "
,
-
1
)
line
=
strings
.
TrimSpace
(
line
)
if
line
==
""
{
continue
}
// reload option
if
strings
.
HasPrefix
(
line
,
"reload "
)
{
var
ss
[]
string
for
_
,
s
:=
range
strings
.
Split
(
line
,
" "
)
{
if
s
=
strings
.
TrimSpace
(
s
);
s
!=
""
{
ss
=
append
(
ss
,
s
)
}
}
if
len
(
ss
)
==
2
{
bp
.
period
,
_
=
time
.
ParseDuration
(
ss
[
1
])
continue
}
}
// reverse option
if
strings
.
HasPrefix
(
line
,
"reverse "
)
{
var
ss
[]
string
for
_
,
s
:=
range
strings
.
Split
(
line
,
" "
)
{
if
s
=
strings
.
TrimSpace
(
s
);
s
!=
""
{
ss
=
append
(
ss
,
s
)
}
}
if
len
(
ss
)
==
2
{
bp
.
reversed
,
_
=
strconv
.
ParseBool
(
ss
[
1
])
continue
}
}
matchers
=
append
(
matchers
,
NewMatcher
(
line
))
}
if
err
:=
scanner
.
Err
();
err
!=
nil
{
return
err
}
bp
.
mux
.
Lock
()
defer
bp
.
mux
.
Unlock
()
bp
.
matchers
=
matchers
return
nil
}
// Period returns the reload period
func
(
bp
*
Bypass
)
Period
()
time
.
Duration
{
return
bp
.
period
}
}
func
(
bp
*
Bypass
)
String
()
string
{
func
(
bp
*
Bypass
)
String
()
string
{
...
...
cmd/gost/bypass.txt
View file @
38827782
# period for live reloading
reload 10s
# matcher reversed
reverse true
10.0.0.1
10.0.0.1
192.168.0.0/24
192.168.0.0/24
172.1.0.0/16
172.1.0.0/16
192.168.100.190/32
192.168.100.190/32
*.example.com
*.example.com
\ No newline at end of file
.example.org
\ No newline at end of file
cmd/gost/cfg.go
View file @
38827782
...
@@ -10,7 +10,6 @@ import (
...
@@ -10,7 +10,6 @@ import (
"io/ioutil"
"io/ioutil"
"net/url"
"net/url"
"os"
"os"
"strconv"
"strings"
"strings"
"time"
"time"
...
@@ -243,22 +242,14 @@ func parseBypass(s string) *gost.Bypass {
...
@@ -243,22 +242,14 @@ func parseBypass(s string) *gost.Bypass {
}
}
matchers
=
append
(
matchers
,
gost
.
NewMatcher
(
s
))
matchers
=
append
(
matchers
,
gost
.
NewMatcher
(
s
))
}
}
return
gost
.
NewBypass
(
matchers
,
reversed
)
return
gost
.
NewBypass
(
reversed
,
matchers
...
)
}
}
f
.
Close
()
scanner
:=
bufio
.
NewScanner
(
f
)
bp
:=
gost
.
NewBypass
(
reversed
)
for
scanner
.
Scan
()
{
go
gost
.
PeriodReload
(
bp
,
s
)
line
:=
scanner
.
Text
()
if
n
:=
strings
.
IndexByte
(
line
,
'#'
);
n
>=
0
{
return
bp
line
=
line
[
:
n
]
}
line
=
strings
.
TrimSpace
(
line
)
if
line
==
""
{
continue
}
matchers
=
append
(
matchers
,
gost
.
NewMatcher
(
line
))
}
return
gost
.
NewBypass
(
matchers
,
reversed
)
}
}
func
parseResolver
(
cfg
string
)
gost
.
Resolver
{
func
parseResolver
(
cfg
string
)
gost
.
Resolver
{
...
@@ -289,59 +280,12 @@ func parseResolver(cfg string) gost.Resolver {
...
@@ -289,59 +280,12 @@ func parseResolver(cfg string) gost.Resolver {
})
})
}
}
}
}
return
gost
.
NewResolver
(
nss
,
timeout
,
ttl
)
return
gost
.
NewResolver
(
timeout
,
ttl
,
nss
...
)
}
}
f
.
Close
()
scanner
:=
bufio
.
NewScanner
(
f
)
resolver
:=
gost
.
NewResolver
(
timeout
,
ttl
)
for
scanner
.
Scan
()
{
go
gost
.
PeriodReload
(
resolver
,
cfg
)
line
:=
scanner
.
Text
()
if
n
:=
strings
.
IndexByte
(
line
,
'#'
);
n
>=
0
{
line
=
line
[
:
n
]
}
line
=
strings
.
TrimSpace
(
line
)
if
line
==
""
{
continue
}
var
ss
[]
string
for
_
,
s
:=
range
strings
.
Split
(
line
,
" "
)
{
if
s
=
strings
.
TrimSpace
(
s
);
s
!=
""
{
ss
=
append
(
ss
,
s
)
}
}
if
len
(
ss
)
==
0
{
return
resolver
continue
}
if
strings
.
ToLower
(
ss
[
0
])
==
"timeout"
{
if
len
(
ss
)
>=
2
{
if
n
,
_
:=
strconv
.
Atoi
(
ss
[
1
]);
n
>
0
{
timeout
=
time
.
Second
*
time
.
Duration
(
n
)
}
}
continue
}
if
strings
.
ToLower
(
ss
[
0
])
==
"ttl"
{
if
len
(
ss
)
>=
2
{
n
,
_
:=
strconv
.
Atoi
(
ss
[
1
])
ttl
=
time
.
Second
*
time
.
Duration
(
n
)
}
continue
}
var
ns
gost
.
NameServer
switch
len
(
ss
)
{
case
1
:
ns
.
Addr
=
ss
[
0
]
case
2
:
ns
.
Addr
=
ss
[
0
]
ns
.
Protocol
=
ss
[
1
]
default
:
ns
.
Addr
=
ss
[
0
]
ns
.
Protocol
=
ss
[
1
]
ns
.
Hostname
=
ss
[
2
]
}
nss
=
append
(
nss
,
ns
)
}
return
gost
.
NewResolver
(
nss
,
timeout
,
ttl
)
}
}
cmd/gost/dns.txt
View file @
38827782
# resolver timeout, default 30s.
# resolver timeout, default 30s.
timeout 10
timeout 10
s
# resolver cache TTL, default 60s, minus value means that cache is disabled.
# resolver cache TTL, default 60s, minus value means that cache is disabled.
ttl 300
ttl 300s
# period for live reloading
reload 10s
# ip[:port] [protocol] [hostname]
# ip[:port] [protocol] [hostname]
...
...
cmd/gost/hosts.txt
View file @
38827782
# period for live reloading
reload 10s
# The following lines are desirable for IPv4 capable hosts
# The following lines are desirable for IPv4 capable hosts
127.0.0.1 localhost
127.0.0.1 localhost
...
@@ -11,4 +14,4 @@
...
@@ -11,4 +14,4 @@
# The following lines are desirable for IPv6 capable hosts
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::2 ip6-allrouters
\ No newline at end of file
cmd/gost/main.go
View file @
38827782
...
@@ -153,7 +153,7 @@ func (r *route) initChain() (*gost.Chain, error) {
...
@@ -153,7 +153,7 @@ func (r *route) initChain() (*gost.Chain, error) {
var
bypass
*
gost
.
Bypass
var
bypass
*
gost
.
Bypass
// global bypass
// global bypass
if
peerCfg
.
Bypass
!=
nil
{
if
peerCfg
.
Bypass
!=
nil
{
bypass
=
gost
.
NewBypassPatterns
(
peerCfg
.
Bypass
.
Patterns
,
peerCfg
.
Bypass
.
Reverse
)
bypass
=
gost
.
NewBypassPatterns
(
peerCfg
.
Bypass
.
Reverse
,
peerCfg
.
Bypass
.
Patterns
...
)
}
}
nodes
=
ngroup
.
Nodes
()
nodes
=
ngroup
.
Nodes
()
for
i
:=
range
nodes
{
for
i
:=
range
nodes
{
...
@@ -492,10 +492,9 @@ func (r *route) serve() error {
...
@@ -492,10 +492,9 @@ func (r *route) serve() error {
var
hosts
*
gost
.
Hosts
var
hosts
*
gost
.
Hosts
if
f
,
_
:=
os
.
Open
(
node
.
Get
(
"hosts"
));
f
!=
nil
{
if
f
,
_
:=
os
.
Open
(
node
.
Get
(
"hosts"
));
f
!=
nil
{
hosts
,
err
=
gost
.
ParseHosts
(
f
)
f
.
Close
()
if
err
!=
nil
{
hosts
=
gost
.
NewHosts
()
log
.
Logf
(
"[hosts] %s: %v"
,
f
.
Name
(),
err
)
go
gost
.
PeriodReload
(
hosts
,
node
.
Get
(
"hosts"
))
}
}
}
handler
.
Init
(
handler
.
Init
(
...
...
hosts.go
View file @
38827782
...
@@ -5,6 +5,7 @@ import (
...
@@ -5,6 +5,7 @@ import (
"io"
"io"
"net"
"net"
"strings"
"strings"
"time"
"github.com/go-log/log"
"github.com/go-log/log"
)
)
...
@@ -17,8 +18,13 @@ type Host struct {
...
@@ -17,8 +18,13 @@ type Host struct {
}
}
// Hosts is a static table lookup for hostnames.
// Hosts is a static table lookup for hostnames.
// For each host a single line should be present with the following information:
// IP_address canonical_hostname [aliases...]
// Fields of the entry are separated by any number of blanks and/or tab characters.
// Text from a "#" character until the end of the line is a comment, and is ignored.
type
Hosts
struct
{
type
Hosts
struct
{
hosts
[]
Host
hosts
[]
Host
period
time
.
Duration
}
}
// NewHosts creates a Hosts with optional list of host
// NewHosts creates a Hosts with optional list of host
...
@@ -28,13 +34,38 @@ func NewHosts(hosts ...Host) *Hosts {
...
@@ -28,13 +34,38 @@ func NewHosts(hosts ...Host) *Hosts {
}
}
}
}
// ParseHosts parses host table from r.
// AddHost adds host(s) to the host table.
// For each host a single line should be present with the following information:
func
(
h
*
Hosts
)
AddHost
(
host
...
Host
)
{
// IP_address canonical_hostname [aliases...]
h
.
hosts
=
append
(
h
.
hosts
,
host
...
)
// Fields of the entry are separated by any number of blanks and/or tab characters.
}
// Text from a "#" character until the end of the line is a comment, and is ignored.
func
ParseHosts
(
r
io
.
Reader
)
(
*
Hosts
,
error
)
{
// Lookup searches the IP address corresponds to the given host from the host table.
hosts
:=
NewHosts
()
func
(
h
*
Hosts
)
Lookup
(
host
string
)
(
ip
net
.
IP
)
{
if
h
==
nil
{
return
}
for
_
,
h
:=
range
h
.
hosts
{
if
h
.
Hostname
==
host
{
ip
=
h
.
IP
break
}
for
_
,
alias
:=
range
h
.
Aliases
{
if
alias
==
host
{
ip
=
h
.
IP
break
}
}
}
if
ip
!=
nil
&&
Debug
{
log
.
Logf
(
"[hosts] hit: %s %s"
,
host
,
ip
.
String
())
}
return
}
// Reload parses config from r, then live reloads the hosts.
func
(
h
*
Hosts
)
Reload
(
r
io
.
Reader
)
error
{
var
hosts
[]
Host
scanner
:=
bufio
.
NewScanner
(
r
)
scanner
:=
bufio
.
NewScanner
(
r
)
for
scanner
.
Scan
()
{
for
scanner
.
Scan
()
{
line
:=
scanner
.
Text
()
line
:=
scanner
.
Text
()
...
@@ -55,6 +86,13 @@ func ParseHosts(r io.Reader) (*Hosts, error) {
...
@@ -55,6 +86,13 @@ func ParseHosts(r io.Reader) (*Hosts, error) {
if
len
(
ss
)
<
2
{
if
len
(
ss
)
<
2
{
continue
// invalid lines are ignored
continue
// invalid lines are ignored
}
}
// reload option
if
strings
.
ToLower
(
ss
[
0
])
==
"reload"
{
h
.
period
,
_
=
time
.
ParseDuration
(
ss
[
1
])
continue
}
ip
:=
net
.
ParseIP
(
ss
[
0
])
ip
:=
net
.
ParseIP
(
ss
[
0
])
if
ip
==
nil
{
if
ip
==
nil
{
continue
// invalid IP addresses are ignored
continue
// invalid IP addresses are ignored
...
@@ -66,39 +104,17 @@ func ParseHosts(r io.Reader) (*Hosts, error) {
...
@@ -66,39 +104,17 @@ func ParseHosts(r io.Reader) (*Hosts, error) {
if
len
(
ss
)
>
2
{
if
len
(
ss
)
>
2
{
host
.
Aliases
=
ss
[
2
:
]
host
.
Aliases
=
ss
[
2
:
]
}
}
hosts
.
AddHost
(
host
)
hosts
=
append
(
hosts
,
host
)
}
}
if
err
:=
scanner
.
Err
();
err
!=
nil
{
if
err
:=
scanner
.
Err
();
err
!=
nil
{
return
nil
,
err
return
err
}
}
return
hosts
,
nil
h
.
hosts
=
hosts
return
nil
}
}
// AddHost adds host(s) to the host table.
// Period returns the reload period
func
(
h
*
Hosts
)
AddHost
(
host
...
Host
)
{
func
(
h
*
Hosts
)
Period
()
time
.
Duration
{
h
.
hosts
=
append
(
h
.
hosts
,
host
...
)
return
h
.
period
}
// Lookup searches the IP address corresponds to the given host from the host table.
func
(
h
*
Hosts
)
Lookup
(
host
string
)
(
ip
net
.
IP
)
{
if
h
==
nil
{
return
}
for
_
,
h
:=
range
h
.
hosts
{
if
h
.
Hostname
==
host
{
ip
=
h
.
IP
break
}
for
_
,
alias
:=
range
h
.
Aliases
{
if
alias
==
host
{
ip
=
h
.
IP
break
}
}
}
if
ip
!=
nil
&&
Debug
{
log
.
Logf
(
"[hosts] hit: %s %s"
,
host
,
ip
.
String
())
}
return
}
}
reload.go
0 → 100644
View file @
38827782
package
gost
import
(
"io"
"os"
"time"
"github.com/go-log/log"
)
// Reloader is the interface for objects that support live reloading.
type
Reloader
interface
{
Reload
(
r
io
.
Reader
)
error
Period
()
time
.
Duration
}
// PeriodReload reloads the config periodically according to the period of the reloader.
func
PeriodReload
(
r
Reloader
,
configFile
string
)
error
{
var
lastMod
time
.
Time
for
{
f
,
err
:=
os
.
Open
(
configFile
)
if
err
!=
nil
{
return
err
}
finfo
,
err
:=
f
.
Stat
()
if
err
!=
nil
{
return
err
}
mt
:=
finfo
.
ModTime
()
if
!
mt
.
Equal
(
lastMod
)
{
if
Debug
{
log
.
Log
(
"[reload]"
,
configFile
)
}
r
.
Reload
(
f
)
lastMod
=
mt
}
f
.
Close
()
period
:=
r
.
Period
()
if
period
<=
0
{
log
.
Log
(
"[reload] disabled:"
,
configFile
)
return
nil
}
if
period
<
time
.
Second
{
period
=
time
.
Second
}
<-
time
.
After
(
period
)
}
}
resolver.go
View file @
38827782
package
gost
package
gost
import
(
import
(
"bufio"
"bytes"
"bytes"
"context"
"context"
"crypto/tls"
"crypto/tls"
"fmt"
"fmt"
"io"
"net"
"net"
"strings"
"strings"
"sync"
"sync"
...
@@ -27,6 +29,12 @@ type Resolver interface {
...
@@ -27,6 +29,12 @@ type Resolver interface {
Resolve
(
host
string
)
([]
net
.
IP
,
error
)
Resolve
(
host
string
)
([]
net
.
IP
,
error
)
}
}
// ReloadResolver is resolover that support live reloading
type
ReloadResolver
interface
{
Resolver
Reloader
}
// NameServer is a name server.
// NameServer is a name server.
// Currently supported protocol: TCP, UDP and TLS.
// Currently supported protocol: TCP, UDP and TLS.
type
NameServer
struct
{
type
NameServer
struct
{
...
@@ -56,13 +64,14 @@ type resolverCacheItem struct {
...
@@ -56,13 +64,14 @@ type resolverCacheItem struct {
type
resolver
struct
{
type
resolver
struct
{
Resolver
*
net
.
Resolver
Resolver
*
net
.
Resolver
Servers
[]
NameServer
Servers
[]
NameServer
mCache
*
sync
.
Map
Timeout
time
.
Duration
Timeout
time
.
Duration
TTL
time
.
Duration
TTL
time
.
Duration
mCache
*
sync
.
Map
period
time
.
Duration
}
}
// NewResolver create a new Resolver with the given name servers and resolution timeout.
// NewResolver create a new Resolver with the given name servers and resolution timeout.
func
NewResolver
(
servers
[]
NameServer
,
timeout
,
ttl
time
.
Duration
)
Resolver
{
func
NewResolver
(
timeout
,
ttl
time
.
Duration
,
servers
...
NameServer
)
Reload
Resolver
{
r
:=
&
resolver
{
r
:=
&
resolver
{
Servers
:
servers
,
Servers
:
servers
,
Timeout
:
timeout
,
Timeout
:
timeout
,
...
@@ -184,6 +193,77 @@ func (r *resolver) storeCache(name string, ips []net.IP) {
...
@@ -184,6 +193,77 @@ func (r *resolver) storeCache(name string, ips []net.IP) {
})
})
}
}
func
(
r
*
resolver
)
Reload
(
rd
io
.
Reader
)
error
{
var
nss
[]
NameServer
scanner
:=
bufio
.
NewScanner
(
rd
)
for
scanner
.
Scan
()
{
line
:=
scanner
.
Text
()
if
n
:=
strings
.
IndexByte
(
line
,
'#'
);
n
>=
0
{
line
=
line
[
:
n
]
}
line
=
strings
.
Replace
(
line
,
"
\t
"
,
" "
,
-
1
)
line
=
strings
.
TrimSpace
(
line
)
if
line
==
""
{
continue
}
var
ss
[]
string
for
_
,
s
:=
range
strings
.
Split
(
line
,
" "
)
{
if
s
=
strings
.
TrimSpace
(
s
);
s
!=
""
{
ss
=
append
(
ss
,
s
)
}
}
if
len
(
ss
)
==
0
{
continue
}
if
len
(
ss
)
>=
2
{
// timeout option
if
strings
.
ToLower
(
ss
[
0
])
==
"timeout"
{
r
.
Timeout
,
_
=
time
.
ParseDuration
(
ss
[
1
])
continue
}
// ttl option
if
strings
.
ToLower
(
ss
[
0
])
==
"ttl"
{
r
.
TTL
,
_
=
time
.
ParseDuration
(
ss
[
1
])
continue
}
// reload option
if
strings
.
ToLower
(
ss
[
0
])
==
"reload"
{
r
.
period
,
_
=
time
.
ParseDuration
(
ss
[
1
])
continue
}
}
var
ns
NameServer
switch
len
(
ss
)
{
case
1
:
ns
.
Addr
=
ss
[
0
]
case
2
:
ns
.
Addr
=
ss
[
0
]
ns
.
Protocol
=
ss
[
1
]
default
:
ns
.
Addr
=
ss
[
0
]
ns
.
Protocol
=
ss
[
1
]
ns
.
Hostname
=
ss
[
2
]
}
nss
=
append
(
nss
,
ns
)
}
if
err
:=
scanner
.
Err
();
err
!=
nil
{
return
err
}
r
.
Servers
=
nss
return
nil
}
func
(
r
*
resolver
)
Period
()
time
.
Duration
{
return
r
.
period
}
func
(
r
*
resolver
)
String
()
string
{
func
(
r
*
resolver
)
String
()
string
{
if
r
==
nil
{
if
r
==
nil
{
return
""
return
""
...
@@ -192,6 +272,7 @@ func (r *resolver) String() string {
...
@@ -192,6 +272,7 @@ func (r *resolver) String() string {
b
:=
&
bytes
.
Buffer
{}
b
:=
&
bytes
.
Buffer
{}
fmt
.
Fprintf
(
b
,
"Timeout %v
\n
"
,
r
.
Timeout
)
fmt
.
Fprintf
(
b
,
"Timeout %v
\n
"
,
r
.
Timeout
)
fmt
.
Fprintf
(
b
,
"TTL %v
\n
"
,
r
.
TTL
)
fmt
.
Fprintf
(
b
,
"TTL %v
\n
"
,
r
.
TTL
)
fmt
.
Fprintf
(
b
,
"Reload %v
\n
"
,
r
.
period
)
for
i
:=
range
r
.
Servers
{
for
i
:=
range
r
.
Servers
{
fmt
.
Fprintln
(
b
,
r
.
Servers
[
i
])
fmt
.
Fprintln
(
b
,
r
.
Servers
[
i
])
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment