11/*
22Technitium DNS Server
33Copyright (C) 2025 Shreyas Zare (shreyas@technitium.com)
4+ Copyright (C) 2025 Zafer Balkan (zafer@zaferbalkan.com)
45
56This program is free software: you can redistribute it and/or modify
67it under the terms of the GNU General Public License as published by
@@ -31,16 +32,7 @@ namespace LogExporter
3132{
3233 public class LogEntry
3334 {
34- public DateTime Timestamp { get ; private set ; }
35- public string ClientIp { get ; private set ; }
36- public DnsTransportProtocol Protocol { get ; private set ; }
37- public DnsServerResponseType ResponseType { get ; private set ; }
38- public double ? ResponseRtt { get ; private set ; }
39- public DnsResponseCode ResponseCode { get ; private set ; }
40- public DnsQuestion ? Question { get ; private set ; }
41- public List < DnsResourceRecord > Answers { get ; private set ; }
42-
43- public LogEntry ( DateTime timestamp , IPEndPoint remoteEP , DnsTransportProtocol protocol , DnsDatagram request , DnsDatagram response )
35+ public LogEntry ( DateTime timestamp , IPEndPoint remoteEP , DnsTransportProtocol protocol , DnsDatagram request , DnsDatagram response , bool ednsLogging = false )
4436 {
4537 // Assign timestamp and ensure it's in UTC
4638 Timestamp = timestamp . Kind == DateTimeKind . Utc ? timestamp : timestamp . ToUniversalTime ( ) ;
@@ -82,31 +74,74 @@ public LogEntry(DateTime timestamp, IPEndPoint remoteEP, DnsTransportProtocol pr
8274 DnssecStatus = record . DnssecStatus ,
8375 } ) ) ;
8476 }
77+
78+ EDNS = new List < EDNSLog > ( ) ;
79+ if ( ! ednsLogging || response . EDNS is null )
80+ {
81+ return ;
82+ }
83+ foreach ( TechnitiumLibrary . Net . Dns . EDnsOptions . EDnsOption extendedErrorLog in response . EDNS . Options . Where ( o => o . Code == TechnitiumLibrary . Net . Dns . EDnsOptions . EDnsOptionCode . EXTENDED_DNS_ERROR ) )
84+ {
85+ string [ ] extractedData = extendedErrorLog . Data . ToString ( ) . Replace ( "[" , string . Empty ) . Replace ( "]" , string . Empty ) . Split ( ":" , StringSplitOptions . TrimEntries ) ;
86+
87+ EDNS . Add ( new EDNSLog
88+ {
89+ ErrType = extractedData [ 0 ] ,
90+ Message = extractedData [ 1 ]
91+ } ) ;
92+ }
93+ }
94+
95+ public List < DnsResourceRecord > Answers { get ; private set ; }
96+ public string ClientIp { get ; private set ; }
97+ public List < EDNSLog > EDNS { get ; private set ; }
98+ public DnsTransportProtocol Protocol { get ; private set ; }
99+ public DnsQuestion ? Question { get ; private set ; }
100+ public DnsResponseCode ResponseCode { get ; private set ; }
101+ public double ? ResponseRtt { get ; private set ; }
102+ public DnsServerResponseType ResponseType { get ; private set ; }
103+ public DateTime Timestamp { get ; private set ; }
104+ public override string ToString ( )
105+ {
106+ return JsonSerializer . Serialize ( this , DnsLogSerializerOptions . Default ) ;
107+ }
108+
109+ public static class DnsLogSerializerOptions
110+ {
111+ public static readonly JsonSerializerOptions Default = new JsonSerializerOptions
112+ {
113+ WriteIndented = false ,
114+ PropertyNamingPolicy = JsonNamingPolicy . CamelCase ,
115+ Converters = { new JsonStringEnumConverter ( ) , new JsonDateTimeConverter ( ) } ,
116+ Encoder = System . Text . Encodings . Web . JavaScriptEncoder . UnsafeRelaxedJsonEscaping ,
117+ NumberHandling = JsonNumberHandling . Strict ,
118+ DefaultIgnoreCondition = JsonIgnoreCondition . WhenWritingNull
119+ } ;
85120 }
86121
87122 public class DnsQuestion
88123 {
124+ public DnsClass QuestionClass { get ; set ; }
89125 public required string QuestionName { get ; set ; }
90126 public DnsResourceRecordType QuestionType { get ; set ; }
91- public DnsClass QuestionClass { get ; set ; }
92127 }
93128
94129 public class DnsResourceRecord
95130 {
131+ public DnssecStatus DnssecStatus { get ; set ; }
96132 public required string Name { get ; set ; }
97- public DnsResourceRecordType RecordType { get ; set ; }
98133 public DnsClass RecordClass { get ; set ; }
99- public uint RecordTtl { get ; set ; }
100134 public required string RecordData { get ; set ; }
101- public DnssecStatus DnssecStatus { get ; set ; }
135+ public uint RecordTtl { get ; set ; }
136+ public DnsResourceRecordType RecordType { get ; set ; }
102137 }
103138
104- public override string ToString ( )
139+ public class EDNSLog
105140 {
106- return JsonSerializer . Serialize ( this , DnsLogSerializerOptions . Default ) ;
141+ public string ErrType { get ; set ; }
142+ public string Message { get ; set ; }
107143 }
108144
109- // Custom DateTime converter to handle UTC serialization in ISO 8601 format
110145 public class JsonDateTimeConverter : JsonConverter < DateTime >
111146 {
112147 public override DateTime Read ( ref Utf8JsonReader reader , Type typeToConvert , JsonSerializerOptions options )
@@ -120,19 +155,5 @@ public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializer
120155 writer . WriteStringValue ( value . ToUniversalTime ( ) . ToString ( "yyyy-MM-ddTHH:mm:ss.fffZ" ) ) ;
121156 }
122157 }
123-
124- // Setup reusable options with a single instance
125- public static class DnsLogSerializerOptions
126- {
127- public static readonly JsonSerializerOptions Default = new JsonSerializerOptions
128- {
129- WriteIndented = false , // Newline delimited logs should not be multiline
130- PropertyNamingPolicy = JsonNamingPolicy . CamelCase , // Convert properties to camelCase
131- Converters = { new JsonStringEnumConverter ( ) , new JsonDateTimeConverter ( ) } , // Handle enums and DateTime conversion
132- Encoder = System . Text . Encodings . Web . JavaScriptEncoder . UnsafeRelaxedJsonEscaping , // For safe encoding
133- NumberHandling = JsonNumberHandling . Strict ,
134- DefaultIgnoreCondition = JsonIgnoreCondition . WhenWritingNull // Ignore null values
135- } ;
136- }
137158 }
138159}
0 commit comments