diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 8101cc9..c4abbd6 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -23,4 +23,4 @@ jobs: with: # This field is required. Dont set the patch version to always use # the latest patch version. - version: v1.51.2 + version: v1.54.1 diff --git a/.golangci.yml b/.golangci.yml index f1ef28f..d6c0b96 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -25,7 +25,6 @@ linters: - ineffassign - staticcheck - unused - - depguard - dupl - gocyclo - goimports diff --git a/README.md b/README.md index 60cb80b..5d27481 100644 --- a/README.md +++ b/README.md @@ -129,48 +129,36 @@ Usage: sniproxy [OPTIONS] Application Options: - --dns-address= IP address that the DNS proxy server will be - listening to. (default: 0.0.0.0) - --dns-port= Port the DNS proxy server will be listening to. - (default: 53) - --dns-upstream= The address of the DNS server the proxy will - forward queries that are not rewritten by - sniproxy. (default: 8.8.8.8) - --dns-redirect-ipv4-to= IPv4 address that will be used for redirecting - type A DNS queries. - --dns-redirect-ipv6-to= IPv6 address that will be used for redirecting - type AAAA DNS queries. - --dns-redirect-rule= Wildcard that defines which domains should be - redirected to the SNI proxy. Can be specified - multiple times. (default: *) - --http-address= IP address the SNI proxy server will be listening - for plain HTTP connections. (default: 0.0.0.0) - --http-port= Port the SNI proxy server will be listening for - plain HTTP connections. (default: 80) - --tls-address= IP address the SNI proxy server will be listening - for TLS connections. (default: 0.0.0.0) - --tls-port= Port the SNI proxy server will be listening for - TLS connections. (default: 443) - --bandwidth-rate= Bytes per second the connections speed will be - limited to. If not set, there is no limit. - (default: 0) - --bandwidth-rule= Allows to define connection speed in bytes/sec - for domains that match the wildcard. Example: - example.*:1024. Can be specified multiple times. - --forward-proxy= Address of a SOCKS/HTTP/HTTPS proxy that the - connections will be forwarded to according to - forward-rule. - --forward-rule= Wildcard that defines what connections will be - forwarded to forward-proxy. Can be specified - multiple times. If no rules are specified, all - connections will be forwarded to the proxy. - --block-rule= Wildcard that defines connections to which - domains should be blocked. Can be specified - multiple times. - --drop-rule= Wildcard that defines connections to which - domains should be dropped (i.e. delayed for a - hard-coded period of 3 minutes. Can be specified - multiple times. + --dns-address= IP address that the DNS proxy server will be listening to. (default: 0.0.0.0) + --dns-port= Port the DNS proxy server will be listening to. (default: 53) + --dns-upstream= The address of the DNS server the proxy will forward queries that are not + rewritten by sniproxy. (default: 8.8.8.8) + --dns-redirect-ipv4-to= IPv4 address that will be used for redirecting type A DNS queries. + --dns-redirect-ipv6-to= IPv6 address that will be used for redirecting type AAAA DNS queries. + --dns-redirect-rule= Wildcard that defines which domains should be redirected to the SNI proxy. Can + be specified multiple times. (default: *) + --dns-drop-rule= Wildcard that defines DNS queries to which domains should be dropped. Can be + specified multiple times. + --http-address= IP address the SNI proxy server will be listening for plain HTTP connections. + (default: 0.0.0.0) + --http-port= Port the SNI proxy server will be listening for plain HTTP connections. + (default: 80) + --tls-address= IP address the SNI proxy server will be listening for TLS connections. + (default: 0.0.0.0) + --tls-port= Port the SNI proxy server will be listening for TLS connections. (default: 443) + --bandwidth-rate= Bytes per second the connections speed will be limited to. If not set, there + is no limit. (default: 0) + --bandwidth-rule= Allows to define connection speed in bytes/sec for domains that match the + wildcard. Example: example.*:1024. Can be specified multiple times. + --forward-proxy= Address of a SOCKS/HTTP/HTTPS proxy that the connections will be forwarded to + according to forward-rule. + --forward-rule= Wildcard that defines what connections will be forwarded to forward-proxy. Can + be specified multiple times. If no rules are specified, all connections will + be forwarded to the proxy. + --block-rule= Wildcard that defines connections to which domains should be blocked. Can be + specified multiple times. + --drop-rule= Wildcard that defines connections to which domains should be dropped (i.e. + delayed for a hard-coded period of 3 minutes. Can be specified multiple times. --verbose Verbose output (optional) --output= Path to the log file. If not set, write to stdout. diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index f235948..cccd3a4 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -29,9 +29,9 @@ func Main() { if err != nil { if flagsErr, ok := err.(*goFlags.Error); ok && flagsErr.Type == goFlags.ErrHelp { os.Exit(0) - } else { - os.Exit(1) } + + os.Exit(1) } if options.Verbose { diff --git a/internal/cmd/config.go b/internal/cmd/config.go index dbdd40a..4423880 100644 --- a/internal/cmd/config.go +++ b/internal/cmd/config.go @@ -21,6 +21,7 @@ func toDNSProxyConfig(options *Options) (cfg *dnsproxy.Config) { ListenAddr: addrPort, Upstream: options.DNSUpstream, RedirectRules: options.DNSRedirectRules, + DropRules: options.DNSDropRules, } if options.DNSRedirectIPV4To != "" { diff --git a/internal/cmd/options.go b/internal/cmd/options.go index f4ed1bc..593343f 100644 --- a/internal/cmd/options.go +++ b/internal/cmd/options.go @@ -29,6 +29,10 @@ type Options struct { // should be redirected to the SNI proxy. Can be specified multiple times. DNSRedirectRules []string `long:"dns-redirect-rule" description:"Wildcard that defines which domains should be redirected to the SNI proxy. Can be specified multiple times." default:"*"` + // DNSDropRules is a list of wildcards that define queries to which domains + // should be dropped. Can be specified multiple times. + DNSDropRules []string `long:"dns-drop-rule" description:"Wildcard that defines DNS queries to which domains should be dropped. Can be specified multiple times."` + // HTTPListenAddress is the IP address the HTTP proxy server will be // listening to. Note, that the HTTP proxy will work pretty much the same // way the SNI proxy works, i.e. it will tunnel traffic to the hostname diff --git a/internal/dnsproxy/config.go b/internal/dnsproxy/config.go index a1b85d8..5a70810 100644 --- a/internal/dnsproxy/config.go +++ b/internal/dnsproxy/config.go @@ -24,4 +24,9 @@ type Config struct { // RedirectRules is a list of wildcards that is used for checking which // domains should be redirected. RedirectRules []string + + // DropRules is a list of wildcards that define DNS queries to which + // domains will be dropped. "Dropped" means that the DNS server will not + // respond to these queries. + DropRules []string } diff --git a/internal/dnsproxy/dnsproxy.go b/internal/dnsproxy/dnsproxy.go index 6d9af9f..6d65afa 100644 --- a/internal/dnsproxy/dnsproxy.go +++ b/internal/dnsproxy/dnsproxy.go @@ -10,7 +10,7 @@ import ( "github.com/AdguardTeam/dnsproxy/proxy" "github.com/AdguardTeam/golibs/log" - "github.com/IGLOU-EU/go-wildcard" + "github.com/ameshkov/sniproxy/internal/filter" "github.com/miekg/dns" ) @@ -24,6 +24,7 @@ type DNSProxy struct { redirectRules []string redirectIPv4To net.IP redirectIPv6To net.IP + dropRules []string } // type check @@ -40,6 +41,7 @@ func New(cfg *Config) (d *DNSProxy, err error) { redirectRules: cfg.RedirectRules, redirectIPv4To: cfg.RedirectIPv4To, redirectIPv6To: cfg.RedirectIPv6To, + dropRules: cfg.DropRules, } d.proxy = &proxy.Proxy{ Config: proxyConfig, @@ -87,12 +89,17 @@ func (d *DNSProxy) requestHandler(p *proxy.Proxy, ctx *proxy.DNSContext) (err er domainName := strings.TrimSuffix(qName, ".") - for _, r := range d.redirectRules { - if wildcard.MatchSimple(r, domainName) { - d.rewrite(qName, qType, ctx) + if filter.MatchWildcards(domainName, d.dropRules) { + // Return empty response, effectively "dropping" the query. + ctx.Res = nil - return nil - } + return nil + } + + if filter.MatchWildcards(domainName, d.redirectRules) { + d.rewrite(qName, qType, ctx) + + return nil } return p.Resolve(ctx) diff --git a/internal/filter/filter.go b/internal/filter/filter.go new file mode 100644 index 0000000..f709f1b --- /dev/null +++ b/internal/filter/filter.go @@ -0,0 +1,16 @@ +// Package filter provides helpers for applying all kinds of rules. +package filter + +import "github.com/IGLOU-EU/go-wildcard" + +// MatchWildcards checks if the string str matches any of the specified +// wildcards. +func MatchWildcards(str string, wildcards []string) (ok bool) { + for _, w := range wildcards { + if wildcard.MatchSimple(w, str) { + return true + } + } + + return false +} diff --git a/internal/sniproxy/sniproxy.go b/internal/sniproxy/sniproxy.go index 87ccf2f..1fccb9c 100644 --- a/internal/sniproxy/sniproxy.go +++ b/internal/sniproxy/sniproxy.go @@ -21,6 +21,7 @@ import ( "github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/netutil" "github.com/IGLOU-EU/go-wildcard" + "github.com/ameshkov/sniproxy/internal/filter" "github.com/ameshkov/sniproxy/internal/shapeio" "golang.org/x/net/proxy" "golang.org/x/time/rate" @@ -219,13 +220,13 @@ func (p *SNIProxy) handleConnection(clientConn net.Conn, plainHTTP bool) (err er log.Info("sniproxy: [%d] start tunneling to %s", ctx.ID, ctx.RemoteAddr) - if p.matchesRules(ctx, p.blockRules) { + if filter.MatchWildcards(ctx.RemoteHost, p.blockRules) { log.Info("sniproxy: [%d] blocked connection to %s", ctx.ID, ctx.RemoteHost) return nil } - if p.matchesRules(ctx, p.dropRules) { + if filter.MatchWildcards(ctx.RemoteHost, p.dropRules) { log.Info("sniproxy: [%d] dropped connection to %s", ctx.ID, ctx.RemoteHost) // Emulate the situation with a connection that was "dropped". @@ -300,19 +301,7 @@ func (p *SNIProxy) shouldForward(ctx *SNIContext) (ok bool) { return true } - return p.matchesRules(ctx, p.forwardRules) -} - -// matchesRules checks if the connection's host matches any of the specified -// wildcards and returns true if there is a match. -func (p *SNIProxy) matchesRules(ctx *SNIContext, rules []string) (ok bool) { - for _, r := range rules { - if wildcard.MatchSimple(r, ctx.RemoteHost) { - return true - } - } - - return false + return filter.MatchWildcards(ctx.RemoteHost, p.forwardRules) } // closeWriter is a helper interface which only purpose is to check if the