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 "iexecuter.h"
17 
18 #include <iostream>
19 #include <sstream>
20 
21 #include "edm_log.h"
22 #include "executer_utils.h"
23 #include "rule_utils.h"
24 
25 namespace OHOS {
26 namespace EDM {
27 namespace IPTABLES {
28 
29 const std::string NEW_OPTION = " -N ";
30 const std::string SELECT_TABLE_OPTION = "-t ";
31 const std::string INSERT_OPTION = " -I ";
32 const std::string APPEND_OPTION = " -A ";
33 const std::string DELETE_OPTION = " -D ";
34 const std::string FLUSH_OPTION = " -F ";
35 const std::string JUMP_OPTION = " -j ";
36 const std::string JUMP_LOG_OPTION = " -j LOG --log-prefix ";
37 const std::string LOG_TAG_DROP = "iptables-edm-drop:";
38 const std::string LOG_TAG_REJECT = "iptables-edm-reject:";
39 const uint32_t RESULT_MIN_SIZE = 3;
40 
IExecuter(std::string chainName)41 IExecuter::IExecuter(std::string chainName) : chainName_(std::move(chainName))
42 {
43     tableName_ = "filter";
44 }
45 
CreateChain()46 ErrCode IExecuter::CreateChain()
47 {
48     std::ostringstream oss;
49     oss << SELECT_TABLE_OPTION << tableName_ << NEW_OPTION << chainName_;
50     std::string result;
51     return ExecuterUtils::GetInstance()->Execute(oss.str(), result);
52 }
53 
Add(const std::shared_ptr<ChainRule> & rule)54 ErrCode IExecuter::Add(const std::shared_ptr<ChainRule>& rule)
55 {
56     if (rule == nullptr) {
57         EDMLOGE("Add: error param.");
58         return EdmReturnErrCode::PARAM_ERROR;
59     }
60     std::ostringstream oss;
61     oss << SELECT_TABLE_OPTION << tableName_;
62     oss << APPEND_OPTION << chainName_;
63     return ExecWithOption(oss, rule);
64 }
65 
Remove(const std::shared_ptr<ChainRule> & rule)66 ErrCode IExecuter::Remove(const std::shared_ptr<ChainRule>& rule)
67 {
68     std::ostringstream oss;
69     oss << SELECT_TABLE_OPTION << tableName_;
70     if (rule == nullptr || rule->Parameter().empty()) {
71         oss << FLUSH_OPTION << chainName_;
72     } else {
73         oss << DELETE_OPTION << chainName_;
74         return ExecWithOption(oss, rule);
75     }
76     std::string result;
77     return ExecuterUtils::GetInstance()->Execute(oss.str(), result);
78 }
79 
ExecWithOption(std::ostringstream & oss,const std::shared_ptr<ChainRule> & rule)80 ErrCode IExecuter::ExecWithOption(std::ostringstream& oss, const std::shared_ptr<ChainRule>& rule)
81 {
82     oss << rule->Parameter();
83     // for interception rules, log needs to be recorded.
84     std::string rulePrefix = oss.str();
85     std::string ruleTarget = rule->Target();
86     if (ruleTarget == REJECT_TARGET) {
87         // no need to use the "" symbol
88         oss << JUMP_LOG_OPTION << LOG_TAG_REJECT;
89     } else if (ruleTarget == DROP_TARGET) {
90         // no need to use the "" symbol
91         oss << JUMP_LOG_OPTION << LOG_TAG_DROP;
92     } else {
93         oss << JUMP_OPTION << rule->Target();
94         std::string result;
95         return ExecuterUtils::GetInstance()->Execute(oss.str(), result);
96     }
97 
98     std::string logRule = oss.str();
99 
100     oss.str({});
101     oss << rulePrefix << JUMP_OPTION << rule->Target();
102     std::string interceptRule = oss.str();
103 
104     std::string result;
105     // "-j LOG" must be before "-j REJECT"/"-j DROP"
106     ErrCode ret = ExecuterUtils::GetInstance()->Execute(logRule, result);
107     if (ret != ERR_OK) {
108         EDMLOGE("ExecWithOption: exec interception rule log fail.");
109     }
110     return ExecuterUtils::GetInstance()->Execute(interceptRule, result);
111 }
112 
GetAll(std::vector<std::string> & ruleList)113 ErrCode IExecuter::GetAll(std::vector<std::string>& ruleList)
114 {
115     std::ostringstream oss;
116     oss << SELECT_TABLE_OPTION << tableName_ << " -n -v -L " << chainName_ << " --line-number";
117     std::string result;
118     ErrCode ret = ExecuterUtils::GetInstance()->Execute(oss.str(), result);
119     if (ret != ERR_OK) {
120         return ret;
121     }
122     std::istringstream iss(result);
123     std::vector<std::string> ruleLines;
124     std::string line;
125     while (getline(iss, line)) {
126         EDMLOGD("GetAll: line: %{public}s", line.c_str());
127         ruleLines.emplace_back(line);
128     }
129     if (ruleLines.size() < RESULT_MIN_SIZE) {
130         EDMLOGI("GetAll: ruleLines is empty");
131         return ERR_OK;
132     }
133 
134     for (uint32_t i = RESULT_MIN_SIZE - 1; i < ruleLines.size(); ++i) {
135         auto index = ruleLines[i].find(LOG_TAG_REJECT);
136         if (index != std::string ::npos) {
137             continue;
138         }
139         index = ruleLines[i].find(LOG_TAG_DROP);
140         if (index != std::string ::npos) {
141             continue;
142         }
143         ruleList.emplace_back(ruleLines[i]);
144     }
145     return ERR_OK;
146 }
147 } // namespace IPTABLES
148 } // namespace EDM
149 } // namespace OHOS