1
+ // Copyright © by Jeff Foley 2017-2025. All rights reserved.
2
+ // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
3
+ // SPDX-License-Identifier: Apache-2.0
4
+
1
5
package dns
2
6
3
7
import (
4
- "errors"
5
- "log/slog "
6
- "time "
7
-
8
- "github.com/miekg/dns"
9
- "github.com/owasp-amass/amass/v4/engine/plugins/support "
10
- et "github.com/owasp-amass/amass/v4/engine/types "
11
- dbt "github.com/owasp-amass/asset-db /types"
12
- oam "github.com/owasp-amass/open- asset-model "
13
- oamdns "github.com/owasp-amass/open-asset-model/dns"
14
- "github.com/owasp-amass/resolve"
8
+ "errors"
9
+ "fmt "
10
+ "log/slog "
11
+ "time"
12
+
13
+ "github.com/miekg/dns "
14
+ "github.com/owasp-amass/amass/v4/engine/plugins/support "
15
+ et "github.com/owasp-amass/amass/v4/engine /types"
16
+ dbt "github.com/owasp-amass/asset-db/types "
17
+ oamdns "github.com/owasp-amass/open-asset-model/dns"
18
+ "github.com/owasp-amass/resolve"
15
19
)
16
20
17
21
type dnsTXT struct {
18
- name string
19
- plugin * dnsPlugin
22
+ name string
23
+ plugin * dnsPlugin
24
+ source * et.Source
20
25
}
21
26
22
27
func (d * dnsTXT ) check (e * et.Event ) error {
23
- _ , ok := e .Entity .Asset .(* oamdns.FQDN )
24
- if ! ok {
25
- slog .Error ("failed to extract the FQDN asset" , "event" , e )
26
- return errors .New ("failed to extract the FQDN asset" )
27
- }
28
-
29
- since , err := support .TTLStartTime (e .Session .Config (), "FQDN" , "FQDN" , d .plugin .name )
30
- if err != nil {
31
- slog .Error ("failed to get TTL start time" , "error" , err , "event" , e )
32
- return err
33
- }
34
-
35
- var txtRecords []* resolve.ExtractedAnswer
36
- src := d .plugin .source
37
- if support .AssetMonitoredWithinTTL (e .Session , e .Entity , src , since ) {
38
- txtRecords = d .lookup (e , e .Entity , since )
39
- } else {
40
- txtRecords = d .query (e , e .Entity )
41
- }
42
-
43
- if len (txtRecords ) > 0 {
44
- d .process (e , e .Entity , txtRecords )
45
- } else {
46
- slog .Warn ("no TXT records found" , "event" , e )
47
- }
48
- return nil
28
+ _ , ok := e .Entity .Asset .(* oamdns.FQDN )
29
+ if ! ok {
30
+ return errors .New ("failed to extract the FQDN asset" )
31
+ }
32
+
33
+ since , err := support .TTLStartTime (e .Session .Config (), "FQDN" , "FQDN" , d .plugin .name )
34
+ if err != nil {
35
+ return err
36
+ }
37
+
38
+ var txtRecords []* resolve.ExtractedAnswer
39
+ if support .AssetMonitoredWithinTTL (e .Session , e .Entity , d .source , since ) {
40
+ txtRecords = d .lookup (e , e .Entity , since )
41
+ } else {
42
+ txtRecords = d .query (e , e .Entity )
43
+ d .store (e , e .Entity , txtRecords )
44
+ }
45
+
46
+ if len (txtRecords ) > 0 {
47
+ d .process (e , e .Entity , txtRecords )
48
+ }
49
+ return nil
49
50
}
50
51
51
52
func (d * dnsTXT ) lookup (e * et.Event , fqdn * dbt.Entity , since time.Time ) []* resolve.ExtractedAnswer {
52
- var txtRecords []* resolve.ExtractedAnswer
53
-
54
- n , ok := fqdn .Asset .(* oamdns.FQDN )
55
- if ! ok || n == nil {
56
- slog .Error ("Failed to cast asset to FQDN" , "event" , e , "fqdn" , fqdn )
57
- return txtRecords
58
- }
59
-
60
- if assets := d .plugin .lookupWithinTTL (e .Session , n .Name , oam .FQDN , since , oam .BasicDNSRelation , int (dns .TypeTXT )); len (assets ) > 0 {
61
- for _ , a := range assets {
62
- txtRecords = append (txtRecords , & resolve.ExtractedAnswer {
63
- Type : dns .TypeTXT ,
64
- Data : a .Asset .(* oamdns.FQDN ).Name ,
65
- })
66
- }
67
- } else {
68
- slog .Warn ("No assets found within TTL" , "event" , e , "fqdn" , fqdn )
69
- }
70
- return txtRecords
53
+ var txtRecords []* resolve.ExtractedAnswer
54
+
55
+ n , ok := fqdn .Asset .(* oamdns.FQDN )
56
+ if ! ok || n == nil {
57
+ return txtRecords
58
+ }
59
+
60
+ if tags , err := e .Session .Cache ().GetEntityTags (fqdn , since , "dns_record" ); err == nil {
61
+ for _ , tag := range tags {
62
+ if prop , ok := tag .Property .(* oamdns.DNSRecordProperty ); ok && prop .Header .RRType == int (dns .TypeTXT ) {
63
+ txtRecords = append (txtRecords , & resolve.ExtractedAnswer {
64
+ Name : n .Name ,
65
+ Type : dns .TypeTXT ,
66
+ Data : prop .Data ,
67
+ })
68
+ }
69
+ }
70
+ }
71
+
72
+ return txtRecords
71
73
}
72
74
73
75
func (d * dnsTXT ) query (e * et.Event , name * dbt.Entity ) []* resolve.ExtractedAnswer {
74
- var txtRecords []* resolve.ExtractedAnswer
75
-
76
- fqdn , ok := name .Asset .(* oamdns.FQDN )
77
- if ! ok {
78
- slog .Error ("Failed to cast asset to FQDN in query" , "event" , e , "name" , name )
79
- return txtRecords
80
- }
81
-
82
- if rr , err := support .PerformQuery (fqdn .Name , dns .TypeTXT ); err == nil {
83
- txtRecords = append (txtRecords , rr ... )
84
- support .MarkAssetMonitored (e .Session , name , d .plugin .source )
85
- } else {
86
- slog .Error ("Failed to perform DNS query" , "error" , err , "event" , e , "fqdn" , fqdn )
87
- }
88
-
89
- return txtRecords
76
+ var txtRecords []* resolve.ExtractedAnswer
77
+
78
+ fqdn , ok := name .Asset .(* oamdns.FQDN )
79
+ if ! ok {
80
+ return txtRecords
81
+ }
82
+
83
+ if rr , err := support .PerformQuery (fqdn .Name , dns .TypeTXT ); err == nil {
84
+ txtRecords = append (txtRecords , rr ... )
85
+ support .MarkAssetMonitored (e .Session , name , d .source )
86
+ }
87
+
88
+ return txtRecords
90
89
}
91
90
92
91
func (d * dnsTXT ) store (e * et.Event , fqdn * dbt.Entity , rr []* resolve.ExtractedAnswer ) {
93
- for _ , record := range rr {
94
- if record .Type != dns .TypeTXT {
95
- continue
96
- }
97
-
98
- txtValue := record .Data
99
-
100
- _ , err := e . Session . Cache (). CreateEntityProperty ( fqdn , & oamdns. DNSRecordProperty {
101
- PropertyName : "dns_record" ,
102
- Header : oamdns. RRHeader {
103
- RRType : 16 ,
104
- Class : 1 ,
105
- TTL : 300 ,
106
- },
107
- Data : txtValue ,
108
- } )
109
- if err != nil {
110
- slog .Error ( "failed to create entity property " , "error " , err , "event " , e , "fqdn" , fqdn , "txtValue" , txtValue )
111
- }
112
- }
92
+ for _ , record := range rr {
93
+ if record .Type != dns .TypeTXT {
94
+ continue
95
+ }
96
+
97
+ txtValue := record .Data
98
+ _ , err := e . Session . Cache (). CreateEntityProperty ( fqdn , & oamdns. DNSRecordProperty {
99
+ PropertyName : "dns_record" ,
100
+ Header : oamdns. RRHeader {
101
+ RRType : int ( dns . TypeTXT ),
102
+ Class : 1 ,
103
+ } ,
104
+ Data : txtValue ,
105
+ })
106
+ if err != nil {
107
+ msg := fmt . Sprintf ( "failed to create entity property for %s: %s" , txtValue , err )
108
+ e . Session . Log (). Error ( msg , "error" , err . Error (),
109
+ slog .Group ( "plugin " , "name " , d . plugin . name , "handler " , d . name ) )
110
+ }
111
+ }
113
112
}
114
113
115
114
func (d * dnsTXT ) process (e * et.Event , fqdn * dbt.Entity , txtRecords []* resolve.ExtractedAnswer ) {
116
- d . store ( e , fqdn , txtRecords )
117
-
118
- for _ , record := range txtRecords {
119
- e . Session . Log (). Info ( "TXT record discovered" , "fqdn" , fqdn . Asset .( * oamdns. FQDN ). Name , "txt" , record . Data , slog .Group ("plugin" , "name" , d .plugin .name , "handler" , d .name ))
120
- }
121
- }
115
+ for _ , record := range txtRecords {
116
+ e . Session . Log (). Info ( "TXT record discovered" , "fqdn" ,
117
+ fqdn . Asset .( * oamdns. FQDN ). Name , "txt" , record . Data ,
118
+ slog .Group ("plugin" , "name" , d .plugin .name , "handler" , d .name ))
119
+ }
120
+ }
0 commit comments