Code
·
142 lines
·
4812 bytes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142/*
https://www.rfc-editor.org/rfc/rfc3225.html
The variable part of an OPT RR may contain zero or more options in
the RDATA. Each option MUST be treated as a bit field. Each option
is encoded as:
+0 (MSB) +1 (LSB)
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0: | OPTION-CODE |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2: | OPTION-LENGTH |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
4: | |
/ OPTION-DATA /
/ /
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
OPTION-CODE
Assigned by the Expert Review process as defined by the DNSEXT
working group and the IESG.
OPTION-LENGTH
Size (in octets) of OPTION-DATA.
OPTION-DATA
Varies per OPTION-CODE. MUST be treated as a bit field.
*/
using MailSharp.DNS.Records;
using System.Buffers.Binary;
using System.Net;
using System.Text;
namespace MailSharp.DNS.Records;
public record RecordOPT : DnsRecord
{
//public ushort UdpPayloadSize { get; init; }
//public byte ExtendedRcode { get; init; }
//public byte Version { get; init; } // moet 0 zijn
//public ushort Flags { get; init; } // bit 0 = DO (DNSSEC OK)
public List<EdnsOption> Options { get; init; } = new();
//public bool DNSSEC_OK => (Flags & 0x8000) != 0;
public RecordOPT(RecordReader rr) : base(rr)
{
// OPT is een pseudo-record: owner = root, type = 41, class = UDP size, TTL = speciaal
//UdpPayloadSize = rr.Class; // "class" veld is hier UDP payload size
//ExtendedRcode = (byte)(rr.Ttl >> 24);
//Version = (byte)(rr.Ttl >> 16);
//Flags = (ushort)(rr.Ttl & 0xFFFF);
ushort rdLength = rr.ReadUInt16(-2); // RDLEN
while (rr.Position < rdLength)
{
ushort code = rr.ReadUInt16();
ushort len = rr.ReadUInt16();
byte[] data = rr.ReadBytes(len);
Options.Add(new EdnsOption(code, data));
}
}
public override string ToString()
{
//var parts = new List<string>
//{
// $"; EDNS: version: {Version}, flags:{(DNSSEC_OK ? " do" : "")}; udp: {UdpPayloadSize}"
//};
//if (Options.Count > 0)
// parts.Add("; " + string.Join("; ", Options));
//if (ExtendedRcode != 0)
// parts.Insert(0, $"; EDE: {ExtendedRcode}");
return "Incomplete";// string.Join(Environment.NewLine, parts);
}
public record EdnsOption(ushort Code, byte[] Data)
{
public override string ToString()
{
return Code switch
{
// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-11
1 => "LLQ", // Legacy
2 => "UL", // Legacy
3 => $"NSID {ToHexOrAscii(Data)}", // NSID
5 => $"DAU {FormatByteList(Data)}", // DNSSEC Algorithm Understood
6 => $"DHU {FormatByteList(Data)}", // DS Hash Understood
7 => $"N3U {FormatByteList(Data)}", // NSEC3 Hash Understood
8 => $"CLIENT-SUBNET {FormatClientSubnet(Data)}", // EDNS Client Subnet (RFC 7871)
9 => $"EXPIRE {BinaryPrimitives.ReadUInt32BigEndian(Data)}",
10 => $"COOKIE {Convert.ToHexString(Data)}",
11 => "TCP-KEEPALIVE", // RFC 7828
12 => $"PADDING {Data.Length} bytes",
13 => "CHAIN", // RFC 7901
14 => $"KEY-TAG {string.Join(" ", Data.Select(b => b.ToString()))}",
15 => "DEVICEID", // Draft
16 => "EXTENDED-ERROR", // RFC 8914
26944 => "PROXY", // Custom, vaak gebruikt
_ => $"OPTION-{Code} {Convert.ToHexString(Data)}"
};
}
private static string ToHexOrAscii(byte[] data)
{
if (data.All(b => b >= 32 && b <= 126))
return $"\"{Encoding.ASCII.GetString(data)}\"";
return Convert.ToHexString(data);
}
private static string FormatByteList(byte[] data) =>
string.Join(" ", data);
private static string FormatClientSubnet(byte[] data)
{
if (data.Length < 4) return Convert.ToHexString(data);
ushort family = BinaryPrimitives.ReadUInt16BigEndian(data);
byte sourcePrefix = data[2];
byte scopePrefix = data[3];
var addrBytes = data.AsSpan(4);
string address = family switch
{
1 => new IPAddress(addrBytes.Slice(0, 4)).ToString(),
2 => new IPAddress(addrBytes.Slice(0, 16)).ToString(),
_ => Convert.ToHexString(addrBytes.ToArray())
};
return $"{family} {address}/{sourcePrefix}/{scopePrefix}";
}
}
}