1+ package dns
2+
3+ 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/open-asset-model/general"
15+ "github.com/owasp-amass/resolve"
16+ )
17+
18+ type dnsTXT struct {
19+ name string
20+ plugin * dnsPlugin
21+ }
22+
23+ type relTXT struct {
24+ txt * dbt.Entity
25+ target * dbt.Entity
26+ }
27+
28+ func (d * dnsTXT ) check (e * et.Event ) error {
29+ _ , ok := e .Entity .Asset .(* oamdns.FQDN )
30+ if ! ok {
31+ return errors .New ("failed to extract the FQDN asset" )
32+ }
33+
34+ since , err := support .TTLStartTime (e .Session .Config (), "FQDN" , "FQDN" , d .plugin .name )
35+ if err != nil {
36+ return err
37+ }
38+
39+ var txtRecords []* relTXT
40+ src := d .plugin .source
41+ if support .AssetMonitoredWithinTTL (e .Session , e .Entity , src , since ) {
42+ txtRecords = append (txtRecords , d .lookup (e , e .Entity , since )... )
43+ } else {
44+ txtRecords = append (txtRecords , d .query (e , e .Entity )... )
45+ }
46+
47+ if len (txtRecords ) > 0 {
48+ d .process (e , txtRecords )
49+ }
50+ return nil
51+ }
52+
53+ func (d * dnsTXT ) lookup (e * et.Event , fqdn * dbt.Entity , since time.Time ) []* relTXT {
54+ var txtRecords []* relTXT
55+
56+ n , ok := fqdn .Asset .(* oamdns.FQDN )
57+ if ! ok || n == nil {
58+ return txtRecords
59+ }
60+
61+ if assets := d .plugin .lookupWithinTTL (e .Session , n .Name , oam .FQDN , since , oam .BasicDNSRelation , 5 ); len (assets ) > 0 {
62+ for _ , a := range assets {
63+ txtRecords = append (txtRecords , & relTXT {txt : fqdn , target : a })
64+ }
65+ }
66+ return txtRecords
67+ }
68+
69+ func (d * dnsTXT ) query (e * et.Event , name * dbt.Entity ) []* relTXT {
70+ var txtRecords []* relTXT
71+
72+ fqdn := name .Asset .(* oamdns.FQDN )
73+ if rr , err := support .PerformQuery (fqdn .Name , dns .TypeTXT ); err == nil {
74+ if records := d .store (e , name , rr ); len (records ) > 0 {
75+ txtRecords = append (txtRecords , records ... )
76+ support .MarkAssetMonitored (e .Session , name , d .plugin .source )
77+ }
78+ }
79+
80+ return txtRecords
81+ }
82+
83+ func (d * dnsTXT ) store (e * et.Event , fqdn * dbt.Entity , rr []* resolve.ExtractedAnswer ) []* relTXT {
84+ var txtRecords []* relTXT
85+
86+ for _ , record := range rr {
87+ if record .Type != dns .TypeTXT {
88+ continue
89+ }
90+
91+ if txt , err := e .Session .Cache ().CreateAsset (& oamdns.FQDN {Name : record .Data }); err == nil && txt != nil {
92+ if edge , err := e .Session .Cache ().CreateEdge (& dbt.Edge {
93+ Relation : & oamdns.BasicDNSRelation {
94+ Name : "dns_record" ,
95+ Header : oamdns.RRHeader {
96+ RRType : int (record .Type ),
97+ Class : 1 ,
98+ },
99+ },
100+ FromEntity : fqdn ,
101+ ToEntity : txt ,
102+ }); err == nil && edge != nil {
103+ txtRecords = append (txtRecords , & relTXT {txt : fqdn , target : txt })
104+ _ , _ = e .Session .Cache ().CreateEdgeProperty (edge , & general.SourceProperty {
105+ Source : d .plugin .source .Name ,
106+ Confidence : d .plugin .source .Confidence ,
107+ })
108+ }
109+ }
110+ }
111+
112+ return txtRecords
113+ }
114+
115+ func (d * dnsTXT ) process (e * et.Event , txtRecords []* relTXT ) {
116+ for _ , a := range txtRecords {
117+ target := a .target .Asset .(* oamdns.FQDN )
118+
119+ _ = e .Dispatcher .DispatchEvent (& et.Event {
120+ Name : target .Name ,
121+ Entity : a .target ,
122+ Session : e .Session ,
123+ })
124+
125+ e .Session .Log ().Info ("relationship discovered" , "from" , d .plugin .source .Name , "relation" ,
126+ "txt_record" , "to" , target .Name , slog .Group ("plugin" , "name" , d .plugin .name , "handler" , d .name ))
127+ }
128+ }
0 commit comments