1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "domain_chain_rule.h"
17
18 #include <algorithm>
19 #include <iostream>
20 #include <sstream>
21 #include <string>
22
23 #include "edm_log.h"
24 #include "rule_utils.h"
25
26 namespace OHOS {
27 namespace EDM {
28 namespace IPTABLES {
29
30 const char DOMAIN_DELIM = '.';
31 const uint32_t DOUBLE_NUM = 2;
32 const uint32_t FOUR_BIT = 4;
33 const uint8_t HEX_TEM_NUM = 10;
34
DomainChainRule(DomainFilterRule domainFilterRule)35 DomainChainRule::DomainChainRule(DomainFilterRule domainFilterRule) : ChainRule(),
36 appUid_(std::get<DOMAIN_APPUID_IND>(domainFilterRule)),
37 domainName_(std::get<DOMAIN_DOMAINNAME_IND>(domainFilterRule))
38 {
39 target_ = RuleUtils::EnumToString(std::get<DOMAIN_ACTION_IND>(domainFilterRule));
40 }
41
DomainChainRule(const std::string & rule)42 DomainChainRule::DomainChainRule(const std::string &rule) : ChainRule(rule)
43 {
44 std::string formatDomain;
45 GetOption(otherOptions_, "owner UID match", appUid_);
46 GetOption(otherOptions_, "STRING match", formatDomain);
47 domainName_ = FormatDataToDomain(formatDomain);
48 }
49
Parameter() const50 std::string DomainChainRule::Parameter() const
51 {
52 // domain type policy uses fixed port and protocol
53 std::ostringstream parameter;
54 parameter << " -p udp --dport 53";
55 if (!appUid_.empty()) {
56 parameter << " -m owner --uid-owner " << appUid_;
57 }
58 if (!domainName_.empty()) {
59 parameter << " -m string --hex-string " << DomainToFormatData(domainName_) << " --algo bm";
60 }
61 return parameter.str();
62 }
63
ToFilterRule()64 DomainFilterRule DomainChainRule::ToFilterRule()
65 {
66 Action action = RuleUtils::StringToAction(target_);
67 return {action, appUid_, domainName_};
68 }
69
DomainToFormatData(const std::string & domainName)70 std::string DomainChainRule::DomainToFormatData(const std::string &domainName)
71 {
72 std::istringstream iss(domainName);
73 std::string segment;
74 std::vector<std::string> segmentArray;
75 while (std::getline(iss, segment, DOMAIN_DELIM)) {
76 segmentArray.emplace_back(segment);
77 }
78
79 // no need to use the "" symbol
80 // www.example.com -> |03|www|07|example|03|com|
81 std::ostringstream domainParameterString;
82 for (const auto &item : segmentArray) {
83 domainParameterString << '|';
84 if (item.length() > 0xf) {
85 domainParameterString << std::hex << item.length();
86 } else {
87 domainParameterString << '0' << std::hex << item.length();
88 }
89 domainParameterString << '|';
90 domainParameterString << item;
91 }
92 domainParameterString << '|';
93 return domainParameterString.str();
94 }
95
FormatDataToDomain(const std::string & formatData)96 std::string DomainChainRule::FormatDataToDomain(const std::string &formatData)
97 {
98 std::string tempFormatData{formatData};
99 std::string invalidChar = "|\"";
100 tempFormatData.erase(std::remove_if(tempFormatData.begin(), tempFormatData.end(),
101 [&invalidChar](const char &c) { return invalidChar.find(c) != std::string::npos; }),
102 tempFormatData.end());
103
104 if (tempFormatData.empty() || tempFormatData.length() % DOUBLE_NUM != 0) {
105 EDMLOGE("FormatDataToDomain: wrong domain data, this should not happen.");
106 return {};
107 }
108
109 std::string ret;
110 std::istringstream iss{tempFormatData};
111 char firstChar;
112 char secondChar;
113 std::vector<std::string> segmentList;
114 while (iss >> firstChar >> secondChar) {
115 uint8_t segmentSize = CharToHex(firstChar, secondChar);
116 std::ostringstream segmentOss;
117 for (uint8_t j = 0; j < segmentSize; ++j) {
118 iss >> firstChar >> secondChar;
119 uint8_t segmentChar = CharToHex(firstChar, secondChar);
120 segmentOss << segmentChar;
121 }
122 segmentList.emplace_back(segmentOss.str());
123 }
124 std::ostringstream oss;
125 for (uint32_t i = 0; i < segmentList.size(); ++i) {
126 oss << segmentList[i];
127 if (i == (segmentList.size() - 1)) {
128 break;
129 }
130 oss << DOMAIN_DELIM;
131 }
132 return oss.str();
133 }
134
CharToHex(const char & first,const char & second)135 uint8_t DomainChainRule::CharToHex(const char &first, const char &second)
136 {
137 uint8_t high = CharToHex(first);
138 uint8_t low = CharToHex(second);
139 return (high << FOUR_BIT) | low;
140 }
141
CharToHex(const char & hexChar)142 uint8_t DomainChainRule::CharToHex(const char &hexChar)
143 {
144 if (hexChar >= '0' && hexChar <= '9') {
145 return hexChar - '0';
146 } else if (hexChar >= 'a' && hexChar <= 'f') {
147 return hexChar - 'a' + HEX_TEM_NUM;
148 } else if (hexChar >= 'A' && hexChar <= 'F') {
149 return hexChar - 'A' + HEX_TEM_NUM;
150 }
151 return 0;
152 }
153 } // namespace IPTABLES
154 } // namespace EDM
155 } // namespace OHOS