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