11package main
22
33import (
4+ "errors"
5+ "fmt"
46 "io/ioutil"
7+ "net"
8+ "os"
59 "path/filepath"
610 "strings"
11+ "sync"
12+ "time"
713 "unicode"
814
915 "github.com/hashicorp/go-immutable-radix"
@@ -22,10 +28,13 @@ const (
2228)
2329
2430type PluginBlockName struct {
31+ sync.Mutex
2532 blockedPrefixes * iradix.Tree
2633 blockedSuffixes * iradix.Tree
2734 blockedSubstrings []string
2835 blockedPatterns []string
36+ outFd * os.File
37+ format string
2938}
3039
3140func (plugin * PluginBlockName ) Name () string {
@@ -100,6 +109,17 @@ func (plugin *PluginBlockName) Init(proxy *Proxy) error {
100109 dlog .Fatal ("Unexpected block type" )
101110 }
102111 }
112+ if len (proxy .blockNameLogFile ) == 0 {
113+ return nil
114+ }
115+ plugin .Lock ()
116+ defer plugin .Unlock ()
117+ outFd , err := os .OpenFile (proxy .blockNameLogFile , os .O_WRONLY | os .O_APPEND | os .O_CREATE , 0644 )
118+ if err != nil {
119+ return err
120+ }
121+ plugin .outFd = outFd
122+ plugin .format = proxy .blockNameFormat
103123 return nil
104124}
105125
@@ -116,30 +136,66 @@ func (plugin *PluginBlockName) Eval(pluginsState *PluginsState, msg *dns.Msg) er
116136 if len (questions ) != 1 {
117137 return nil
118138 }
119- question := strings .ToLower (StripTrailingDot (questions [0 ].Name ))
120- revQuestion := StringReverse (question )
121- match , _ , found := plugin .blockedSuffixes .Root ().LongestPrefix ([]byte (revQuestion ))
122- if found {
123- if len (match ) == len (question ) || question [len (match )] == '.' {
124- pluginsState .action = PluginsActionReject
125- return nil
139+ qName := strings .ToLower (StripTrailingDot (questions [0 ].Name ))
140+ revQname := StringReverse (qName )
141+ reject , reason := false , ""
142+ if ! reject {
143+ match , _ , found := plugin .blockedSuffixes .Root ().LongestPrefix ([]byte (revQname ))
144+ if found {
145+ if len (match ) == len (qName ) || qName [len (match )] == '.' {
146+ reject , reason = true , "*" + string (match )
147+ }
126148 }
127149 }
128- _ , _ , found = plugin .blockedPrefixes .Root ().LongestPrefix ([]byte (question ))
129- if found {
130- pluginsState .action = PluginsActionReject
131- return nil
150+ if ! reject {
151+ match , _ , found := plugin .blockedPrefixes .Root ().LongestPrefix ([]byte (qName ))
152+ if found {
153+ reject , reason = true , string (match )+ "*"
154+ }
132155 }
133- for _ , substring := range plugin .blockedSubstrings {
134- if strings .Contains (substring , question ) {
135- pluginsState .action = PluginsActionReject
136- return nil
156+ if ! reject {
157+ for _ , substring := range plugin .blockedSubstrings {
158+ if strings .Contains (substring , qName ) {
159+ reject , reason = true , "*" + substring + "*"
160+ break
161+ }
162+ }
163+ }
164+ if ! reject {
165+ for _ , pattern := range plugin .blockedPatterns {
166+ if found , _ := filepath .Match (pattern , qName ); found {
167+ reject , reason = true , pattern
168+ break
169+ }
137170 }
138171 }
139- for _ , pattern := range plugin .blockedPatterns {
140- if found , _ := filepath .Match (pattern , question ); found {
141- pluginsState .action = PluginsActionReject
142- return nil
172+ if reject {
173+ pluginsState .action = PluginsActionReject
174+ if plugin .outFd != nil {
175+ var clientIPStr string
176+ if pluginsState .clientProto == "udp" {
177+ clientIPStr = (* pluginsState .clientAddr ).(* net.UDPAddr ).IP .String ()
178+ } else {
179+ clientIPStr = (* pluginsState .clientAddr ).(* net.TCPAddr ).IP .String ()
180+ }
181+ var line string
182+ if plugin .format == "tsv" {
183+ now := time .Now ()
184+ year , month , day := now .Date ()
185+ hour , minute , second := now .Clock ()
186+ tsStr := fmt .Sprintf ("[%d-%02d-%02d %02d:%02d:%02d]" , year , int (month ), day , hour , minute , second )
187+ line = fmt .Sprintf ("%s\t %s\t %s\t %s\n " , tsStr , clientIPStr , StringQuote (qName ), StringQuote (reason ))
188+ } else if plugin .format == "ltsv" {
189+ line = fmt .Sprintf ("time:%d\t host:%s\t qname:%s\t message:%s\n " , time .Now ().Unix (), clientIPStr , StringQuote (qName ), StringQuote (reason ))
190+ } else {
191+ dlog .Fatalf ("Unexpected log format: [%s]" , plugin .format )
192+ }
193+ plugin .Lock ()
194+ if plugin .outFd == nil {
195+ return errors .New ("Log file not initialized" )
196+ }
197+ plugin .outFd .WriteString (line )
198+ defer plugin .Unlock ()
143199 }
144200 }
145201 return nil
0 commit comments