1 /*
2 * Copyright (c) 2021, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "common/dns_utils.hpp"
30
31 #include <assert.h>
32
33 #include "common/code_utils.hpp"
34
NameEndsWithDot(const std::string & aName)35 static bool NameEndsWithDot(const std::string &aName)
36 {
37 return !aName.empty() && aName.back() == '.';
38 }
39
SplitFullDnsName(const std::string & aName)40 DnsNameInfo SplitFullDnsName(const std::string &aName)
41 {
42 size_t transportPos;
43 DnsNameInfo nameInfo;
44 std::string fullName = aName;
45
46 if (!NameEndsWithDot(fullName))
47 {
48 fullName += '.';
49 }
50
51 transportPos = fullName.rfind("._udp.");
52
53 if (transportPos == std::string::npos)
54 {
55 transportPos = fullName.rfind("._tcp.");
56 }
57
58 if (transportPos == std::string::npos)
59 {
60 // host.domain or domain
61 size_t dotPos = fullName.find_first_of('.');
62
63 assert(dotPos != std::string::npos);
64
65 // host.domain
66 nameInfo.mHostName = fullName.substr(0, dotPos);
67 nameInfo.mDomain = fullName.substr(dotPos + 1, fullName.length() - dotPos - 1);
68 }
69 else
70 {
71 // service or service instance
72 size_t dotPos = transportPos > 0 ? fullName.find_last_of('.', transportPos - 1) : std::string::npos;
73
74 nameInfo.mDomain = fullName.substr(transportPos + 6); // 6 is the length of "._tcp." or "._udp."
75
76 if (dotPos == std::string::npos)
77 {
78 // service.domain
79 nameInfo.mServiceName = fullName.substr(0, transportPos + 5);
80 }
81 else
82 {
83 // instance.service.domain
84 nameInfo.mInstanceName = fullName.substr(0, dotPos);
85 nameInfo.mServiceName = fullName.substr(dotPos + 1, transportPos + 4 - dotPos);
86 }
87 }
88
89 if (!NameEndsWithDot(nameInfo.mDomain))
90 {
91 nameInfo.mDomain += '.';
92 }
93
94 return nameInfo;
95 }
96
SplitFullServiceInstanceName(const std::string & aFullName,std::string & aInstanceName,std::string & aType,std::string & aDomain)97 otbrError SplitFullServiceInstanceName(const std::string &aFullName,
98 std::string & aInstanceName,
99 std::string & aType,
100 std::string & aDomain)
101 {
102 otbrError error = OTBR_ERROR_NONE;
103 DnsNameInfo nameInfo = SplitFullDnsName(aFullName);
104
105 VerifyOrExit(nameInfo.IsServiceInstance(), error = OTBR_ERROR_INVALID_ARGS);
106
107 aInstanceName = std::move(nameInfo.mInstanceName);
108 aType = std::move(nameInfo.mServiceName);
109 aDomain = std::move(nameInfo.mDomain);
110
111 exit:
112 return error;
113 }
114
SplitFullServiceName(const std::string & aFullName,std::string & aType,std::string & aDomain)115 otbrError SplitFullServiceName(const std::string &aFullName, std::string &aType, std::string &aDomain)
116 {
117 otbrError error = OTBR_ERROR_NONE;
118 DnsNameInfo nameInfo = SplitFullDnsName(aFullName);
119
120 VerifyOrExit(nameInfo.IsService(), error = OTBR_ERROR_INVALID_ARGS);
121
122 aType = std::move(nameInfo.mServiceName);
123 aDomain = std::move(nameInfo.mDomain);
124
125 exit:
126 return error;
127 }
128
SplitFullHostName(const std::string & aFullName,std::string & aHostName,std::string & aDomain)129 otbrError SplitFullHostName(const std::string &aFullName, std::string &aHostName, std::string &aDomain)
130 {
131 otbrError error = OTBR_ERROR_NONE;
132 DnsNameInfo nameInfo = SplitFullDnsName(aFullName);
133
134 VerifyOrExit(nameInfo.IsHost(), error = OTBR_ERROR_INVALID_ARGS);
135
136 aHostName = std::move(nameInfo.mHostName);
137 aDomain = std::move(nameInfo.mDomain);
138
139 exit:
140 return error;
141 }
142