Merge remote-tracking branch 'github/master'
[mono.git] / mcs / class / System / Mono.Net.Dns / DnsUtil.cs
1 //
2 // Mono.Net.Dns.DnsUtil
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo.mono@gmail.com)
6 //
7 // Copyright 2011 Gonzalo Paniagua Javier
8 //
9 // Licensed under the Apache License, Version 2.0 (the "License");
10 // you may not use this file except in compliance with the License.
11 // You may obtain a copy of the License at
12 //
13 // http://www.apache.org/licenses/LICENSE-2.0
14 //
15 // Unless required by applicable law or agreed to in writing, software
16 // distributed under the License is distributed on an "AS IS" BASIS,
17 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 // See the License for the specific language governing permissions and
19 // limitations under the License.
20 //
21 using System;
22 using System.Collections.Generic;
23 using System.Text;
24
25 namespace Mono.Net.Dns {
26         static class DnsUtil {
27                 // RFC 2181 - Section 11
28                 public static bool IsValidDnsName (string name)
29                 {
30                         if (name == null)
31                                 return false;
32
33                         int len = name.Length;
34                         if (len > 255)
35                                 return false;
36                         int part_length = 0;
37                         for (int i = 0; i < len; i++) {
38                                 char c = name [i];
39                                 if (c == '.') {
40                                         if (i == 0 && len > 1)
41                                                 return false; // Can't begin with a dot unless it's "."
42                                         if (i > 0 && part_length == 0)
43                                                 return false; // No ".." allowed
44                                         part_length = 0;
45                                         continue;
46                                 }
47                                 part_length++;
48                                 if (part_length > 63)
49                                         return false;
50                         }
51                         return true;
52                 }
53
54                 public static int GetEncodedLength (string name)
55                 {
56                         if (!IsValidDnsName (name))
57                                 return -1;
58
59                         if (name == String.Empty)
60                                 return 1;
61
62                         int len = name.Length;
63                         if (name [len - 1] == '.')
64                                 return len + 1; // (length + label + ... + \0)
65                         return len + 2; // need 1 more for the second to last label length
66                 }
67
68                 public static int GetNameLength (byte [] buffer)
69                 {
70                         return GetNameLength (buffer, 0);
71                 }
72
73                 public static int GetNameLength (byte [] buffer, int offset)
74                 {
75                         if (buffer == null)
76                                 throw new ArgumentNullException ("buffer");
77                         if (offset < 0 || offset >= buffer.Length)
78                                 throw new ArgumentOutOfRangeException ("offset");
79
80                         int i = 0;
81                         int len = 0;
82                         while (len < 256) {
83                                 i = buffer [offset++];
84                                 if (i == 0)
85                                         return len > 0 ? --len : 0;
86                                 int ptr = i & 0x0C0;
87                                 if (ptr == 0x0C0) {
88                                         i = ((ptr & 0x3F) << 8) + buffer[offset++];
89                                         offset = i;
90                                         continue;
91                                 } else if (ptr >= 0x40) {
92                                         return -2; // Invalid ptr
93                                 }
94                                 len += i + 1;
95                                 offset += i;
96                         }
97                         return -1; // Invalid length
98                 }
99
100                 public static string ReadName (byte [] buffer, ref int offset)
101                 {
102                         if (buffer == null)
103                                 throw new ArgumentNullException ("buffer");
104                         if (offset < 0 || offset >= buffer.Length)
105                                 throw new ArgumentOutOfRangeException ("offset");
106
107                         StringBuilder sb = new StringBuilder (32);
108                         int i = 0;
109                         bool no_ptr = true;
110                         int off = offset;
111                         while (sb.Length < 256) {
112                                 i = buffer [off++];
113                                 if (no_ptr) offset++;
114                                 if (i == 0) {
115                                         if (sb.Length > 0)
116                                                 sb.Length--;
117                                         return sb.ToString ();
118                                 }
119                                 int ptr = i & 0x0C0;
120                                 if (ptr == 0x0C0) {
121                                         i = ((ptr & 0x3F) << 8) + buffer [off];
122                                         if (no_ptr) offset++;
123                                         no_ptr = false;
124                                         off = i;
125                                         continue;
126                                 } else if (i >= 0x40) {
127                                         return null; // Invalid ptr
128                                 }
129
130                                 for (int k = 0; k < i; k++)
131                                         sb.Append ((char) buffer [off + k]);
132                                 sb.Append ('.');
133                                 off += i;
134                                 if (no_ptr) offset += i;
135                         }
136                         return null;  // never reached
137                 }
138
139         }
140 }
141