1package resolver 2 3import ( 4 "context" 5 "time" 6 7 "github.com/ooni/probe-engine/legacy/netx/dialid" 8 "github.com/ooni/probe-engine/legacy/netx/modelx" 9 "github.com/ooni/probe-engine/legacy/netx/transactionid" 10) 11 12// EmitterTransport is a RoundTripper that emits events when they occur. 13type EmitterTransport struct { 14 RoundTripper 15} 16 17// RoundTrip implements RoundTripper.RoundTrip 18func (txp EmitterTransport) RoundTrip(ctx context.Context, querydata []byte) ([]byte, error) { 19 root := modelx.ContextMeasurementRootOrDefault(ctx) 20 root.Handler.OnMeasurement(modelx.Measurement{ 21 DNSQuery: &modelx.DNSQueryEvent{ 22 Data: querydata, 23 DialID: dialid.ContextDialID(ctx), 24 DurationSinceBeginning: time.Now().Sub(root.Beginning), 25 }, 26 }) 27 replydata, err := txp.RoundTripper.RoundTrip(ctx, querydata) 28 if err != nil { 29 return nil, err 30 } 31 root.Handler.OnMeasurement(modelx.Measurement{ 32 DNSReply: &modelx.DNSReplyEvent{ 33 Data: replydata, 34 DialID: dialid.ContextDialID(ctx), 35 DurationSinceBeginning: time.Now().Sub(root.Beginning), 36 }, 37 }) 38 return replydata, nil 39} 40 41// EmitterResolver is a resolver that emits events 42type EmitterResolver struct { 43 Resolver 44} 45 46// LookupHost returns the IP addresses of a host 47func (r EmitterResolver) LookupHost(ctx context.Context, hostname string) ([]string, error) { 48 var ( 49 network string 50 address string 51 ) 52 type queryableResolver interface { 53 Transport() RoundTripper 54 } 55 if qr, ok := r.Resolver.(queryableResolver); ok { 56 txp := qr.Transport() 57 network, address = txp.Network(), txp.Address() 58 } 59 dialID := dialid.ContextDialID(ctx) 60 txID := transactionid.ContextTransactionID(ctx) 61 root := modelx.ContextMeasurementRootOrDefault(ctx) 62 root.Handler.OnMeasurement(modelx.Measurement{ 63 ResolveStart: &modelx.ResolveStartEvent{ 64 DialID: dialID, 65 DurationSinceBeginning: time.Now().Sub(root.Beginning), 66 Hostname: hostname, 67 TransactionID: txID, 68 TransportAddress: address, 69 TransportNetwork: network, 70 }, 71 }) 72 addrs, err := r.Resolver.LookupHost(ctx, hostname) 73 root.Handler.OnMeasurement(modelx.Measurement{ 74 ResolveDone: &modelx.ResolveDoneEvent{ 75 Addresses: addrs, 76 DialID: dialID, 77 DurationSinceBeginning: time.Now().Sub(root.Beginning), 78 Error: err, 79 Hostname: hostname, 80 TransactionID: txID, 81 TransportAddress: address, 82 TransportNetwork: network, 83 }, 84 }) 85 return addrs, err 86} 87 88var _ RoundTripper = EmitterTransport{} 89var _ Resolver = EmitterResolver{} 90