Skip to content

Commit

Permalink
Added dns-drop-rules
Browse files Browse the repository at this point in the history
  • Loading branch information
ameshkov committed Sep 14, 2023
1 parent 4885ba0 commit e04ab5e
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 67 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 0 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ linters:
- ineffassign
- staticcheck
- unused
- depguard
- dupl
- gocyclo
- goimports
Expand Down
72 changes: 30 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions internal/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions internal/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 != "" {
Expand Down
4 changes: 4 additions & 0 deletions internal/cmd/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions internal/dnsproxy/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
19 changes: 13 additions & 6 deletions internal/dnsproxy/dnsproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -24,6 +24,7 @@ type DNSProxy struct {
redirectRules []string
redirectIPv4To net.IP
redirectIPv6To net.IP
dropRules []string
}

// type check
Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
16 changes: 16 additions & 0 deletions internal/filter/filter.go
Original file line number Diff line number Diff line change
@@ -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
}
19 changes: 4 additions & 15 deletions internal/sniproxy/sniproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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".
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit e04ab5e

Please sign in to comment.