1 /*
2 * Copyright (c) 2021-2025 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 #include "softbus_ddos.h"
16
17 #include <securec.h>
18 #include <time.h>
19
20 #include "anonymizer.h"
21 #include "lnn_log.h"
22 #include "softbus_adapter_mem.h"
23 #include "softbus_error_code.h"
24 #include "softbus_utils.h"
25 #include "legacy/softbus_hidumper_buscenter.h"
26
27 #define TABLE_COLUMNS 3
28 #define SAME_USER_SAME_ID_TIMES 100
29 #define USE_SAME_GET_DEVICE_INFO_ID_TIMES 300
30 #define ALL_USER_SAME_ID_TIMES 800
31 #define SAME_USER_ALL_ID_TIMES 1000
32 #define ALL_USER_ALL_ID_TIMES 2000
33 #define DDOS_HIDUMP_ENABLE "DdosHiDumperEnable"
34 #define DDOS_HIDUMP_DISABLE "DdosHiDumperDisable"
35
36 static SoftBusList* g_callRecord = NULL;
37 static bool g_isEnable = true;
38
SetDdosStateEnable(int fd)39 static int32_t SetDdosStateEnable(int fd)
40 {
41 g_isEnable = true;
42 SOFTBUS_DPRINTF(fd, "%s\n", "ddos already set true");
43 return SOFTBUS_OK;
44 }
45
SetDdosStateDisable(int fd)46 static int32_t SetDdosStateDisable(int fd)
47 {
48 g_isEnable = false;
49 SOFTBUS_DPRINTF(fd, "%s\n", "ddos already set false");
50 return SOFTBUS_OK;
51 }
52
IsEnableDdos()53 static bool IsEnableDdos()
54 {
55 return g_isEnable;
56 }
57
DdosHiDumperRegister()58 static int32_t DdosHiDumperRegister()
59 {
60 int32_t ret = SoftBusRegBusCenterVarDump(DDOS_HIDUMP_ENABLE, &SetDdosStateEnable);
61 LNN_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, LNN_EVENT, "regist ddos enable failed ret=%{public}d", ret);
62 ret = SoftBusRegBusCenterVarDump(DDOS_HIDUMP_DISABLE, &SetDdosStateDisable);
63 LNN_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, ret, LNN_EVENT, "regist ddos disable failed ret=%{public}d", ret);
64 return SOFTBUS_OK;
65 }
66
67 static int32_t callTable[SOFTBUS_FUNC_ID_BUIT][TABLE_COLUMNS] = {
68 [SERVER_JOIN_LNN] = {SAME_USER_SAME_ID_TIMES, ALL_USER_SAME_ID_TIMES},
69 [SERVER_LEAVE_LNN] = {SAME_USER_SAME_ID_TIMES, ALL_USER_SAME_ID_TIMES},
70 [SERVER_GET_ALL_ONLINE_NODE_INFO] = {USE_SAME_GET_DEVICE_INFO_ID_TIMES, ALL_USER_SAME_ID_TIMES},
71 [SERVER_GET_LOCAL_DEVICE_INFO] = {USE_SAME_GET_DEVICE_INFO_ID_TIMES, ALL_USER_SAME_ID_TIMES},
72 [SERVER_SET_NODE_DATA_CHANGE_FLAG] = {SAME_USER_SAME_ID_TIMES, ALL_USER_SAME_ID_TIMES},
73 [SERVER_GET_NODE_KEY_INFO] = {USE_SAME_GET_DEVICE_INFO_ID_TIMES, ALL_USER_SAME_ID_TIMES},
74 [SERVER_START_TIME_SYNC] = {SAME_USER_SAME_ID_TIMES, ALL_USER_SAME_ID_TIMES},
75 [SERVER_STOP_TIME_SYNC] = {SAME_USER_SAME_ID_TIMES, ALL_USER_SAME_ID_TIMES},
76 [SERVER_PUBLISH_LNN] = {SAME_USER_SAME_ID_TIMES, ALL_USER_SAME_ID_TIMES},
77 [SERVER_STOP_PUBLISH_LNN] = {SAME_USER_SAME_ID_TIMES, ALL_USER_SAME_ID_TIMES},
78 [SERVER_REFRESH_LNN] = {SAME_USER_SAME_ID_TIMES, ALL_USER_SAME_ID_TIMES},
79 [SERVER_STOP_REFRESH_LNN] = {SAME_USER_SAME_ID_TIMES, ALL_USER_SAME_ID_TIMES},
80 [SERVER_ACTIVE_META_NODE] = {SAME_USER_SAME_ID_TIMES, ALL_USER_SAME_ID_TIMES},
81 [SERVER_DEACTIVE_META_NODE] = {SAME_USER_SAME_ID_TIMES, ALL_USER_SAME_ID_TIMES},
82 [SERVER_GET_ALL_META_NODE_INFO] = {USE_SAME_GET_DEVICE_INFO_ID_TIMES, ALL_USER_SAME_ID_TIMES},
83 [SERVER_SHIFT_LNN_GEAR] = {SAME_USER_SAME_ID_TIMES, ALL_USER_SAME_ID_TIMES},
84 [SERVER_SYNC_TRUSTED_RELATION] = {SAME_USER_SAME_ID_TIMES, ALL_USER_SAME_ID_TIMES},
85 };
86
CallRecordLock(void)87 static int32_t CallRecordLock(void)
88 {
89 return SoftBusMutexLock(&g_callRecord->lock);
90 }
91
CallRecordUnlock(void)92 static void CallRecordUnlock(void)
93 {
94 (void)SoftBusMutexUnlock(&g_callRecord->lock);
95 }
96
CreateAndAddCallRecord(const char * pkgName,int interfaceId)97 static CallRecord* CreateAndAddCallRecord(const char* pkgName, int interfaceId)
98 {
99 CallRecord* newRecord = (CallRecord*)SoftBusCalloc(sizeof(CallRecord));
100 if (newRecord == NULL) {
101 LNN_LOGE(LNN_EVENT, "newRecord malloc fail");
102 return NULL;
103 }
104 if (strcpy_s(newRecord->pkgName, PKG_NAME_SIZE_MAX, pkgName) != EOK) {
105 LNN_LOGE(LNN_EVENT, "strcpy pkgName fail");
106 SoftBusFree(newRecord);
107 return NULL;
108 }
109 newRecord->interfaceId = interfaceId;
110 newRecord->timestamp = time(NULL);
111 ListAdd(&g_callRecord->list, &newRecord->node);
112 g_callRecord->cnt++;
113 return newRecord;
114 }
115
QueryCallRecord(const char * pkgName,enum SoftBusFuncId interfaceId)116 static int32_t QueryCallRecord(const char* pkgName, enum SoftBusFuncId interfaceId)
117 {
118 CallRecord *next = NULL;
119 CallRecord *item = NULL;
120 int32_t userCount = 1;
121 int32_t idCount = 1;
122 int32_t recordCount = 1;
123 LIST_FOR_EACH_ENTRY_SAFE(item, next, &g_callRecord->list, CallRecord, node) {
124 if (strncmp(item->pkgName, pkgName, PKG_NAME_SIZE_MAX) == 0) {
125 userCount++;
126 }
127 if (item->interfaceId == interfaceId) {
128 idCount++;
129 if (strncmp(item->pkgName, pkgName, PKG_NAME_SIZE_MAX) == 0) {
130 recordCount++;
131 }
132 }
133 }
134 LNN_LOGE(LNN_EVENT,
135 "recordCount=%{public}d, idCount=%{public}d, userCount=%{public}d, totalCount=%{public}d, funcid=%{public}d",
136 recordCount, idCount, userCount, g_callRecord->cnt, interfaceId);
137 int column = 0;
138 if (recordCount > callTable[interfaceId][column++]) {
139 return SOFTBUS_DDOS_ID_AND_USER_SAME_COUNT_LIMIT;
140 } else if (idCount > callTable[interfaceId][column++]) {
141 return SOFTBUS_DDOS_ID_SAME_COUNT_LIMIT;
142 } else if (userCount > SAME_USER_ALL_ID_TIMES) {
143 return SOFTBUS_DDOS_USER_SAME_ID_COUNT_LIMIT;
144 } else if (g_callRecord->cnt > ALL_USER_ALL_ID_TIMES) {
145 return SOFTBUS_DDOS_USER_ID_ALL_COUNT_LIMIT;
146 } else {
147 return SOFTBUS_OK;
148 }
149 }
150
ClearExpiredRecords(void)151 static void ClearExpiredRecords(void)
152 {
153 if (CallRecordLock() != SOFTBUS_OK) {
154 LNN_LOGE(LNN_EVENT, "CallRecord lock fail");
155 return;
156 }
157 time_t currentTime = time(NULL);
158 CallRecord *next = NULL;
159 CallRecord *item = NULL;
160 LIST_FOR_EACH_ENTRY_SAFE(item, next, &g_callRecord->list, CallRecord, node) {
161 if (currentTime - item->timestamp > TIME_THRESHOLD_SIZE) {
162 ListDelete(&item->node);
163 SoftBusFree(item);
164 g_callRecord->cnt--;
165 }
166 }
167 CallRecordUnlock();
168 }
169
IsInterfaceFuncIdValid(enum SoftBusFuncId interfaceId)170 static int32_t IsInterfaceFuncIdValid(enum SoftBusFuncId interfaceId)
171 {
172 if ((interfaceId < 0) || (interfaceId >= SOFTBUS_FUNC_ID_BUIT)) {
173 return false;
174 }
175 return true;
176 }
177
IsOverThreshold(const char * pkgName,enum SoftBusFuncId interfaceId)178 int32_t IsOverThreshold(const char* pkgName, enum SoftBusFuncId interfaceId)
179 {
180 if (!IsEnableDdos()) {
181 LNN_LOGE(LNN_EVENT, "ddos not enable");
182 return SOFTBUS_DDOS_DISABLE;
183 }
184 if (pkgName == NULL || !IsInterfaceFuncIdValid(interfaceId)) {
185 LNN_LOGE(LNN_EVENT, "pkgName or id is invalid, interfaceId=%{public}d", interfaceId);
186 return SOFTBUS_INVALID_PARAM;
187 }
188 if (CallRecordLock() != SOFTBUS_OK) {
189 LNN_LOGE(LNN_EVENT, "CallRecord lock fail");
190 return SOFTBUS_LOCK_ERR;
191 }
192 ClearExpiredRecords();
193 int32_t ret = QueryCallRecord(pkgName, interfaceId);
194 if (ret != SOFTBUS_OK) {
195 char *tmpName = NULL;
196 Anonymize(pkgName, &tmpName);
197 LNN_LOGE(LNN_EVENT, "use over limit ret=%{public}d, pkgName=%{public}s, interfaceId=%{public}d",
198 ret, AnonymizeWrapper(tmpName), interfaceId);
199 AnonymizeFree(tmpName);
200 CallRecordUnlock();
201 return ret;
202 }
203 CallRecord* record = CreateAndAddCallRecord(pkgName, interfaceId);
204 if (record == NULL) {
205 LNN_LOGE(LNN_EVENT, "create callrecord failed");
206 CallRecordUnlock();
207 return SOFTBUS_INVALID_PARAM;
208 }
209 CallRecordUnlock();
210 return ret;
211 }
212
RegisterClearRecordsTimer(void)213 static void RegisterClearRecordsTimer(void)
214 {
215 int32_t ret = RegisterTimeoutCallback(SOFTBUS_DDOS_TIMER_FUN, ClearExpiredRecords);
216 if (ret != SOFTBUS_OK) {
217 LNN_LOGE(LNN_EVENT, "regist callback failed ret=%{public}d", ret);
218 }
219 }
220
InitDdos(void)221 int32_t InitDdos(void)
222 {
223 if (g_callRecord != NULL) {
224 return SOFTBUS_OK;
225 }
226 g_callRecord = CreateSoftBusList();
227 if (g_callRecord == NULL) {
228 LNN_LOGE(LNN_EVENT, "create callRecord list fail");
229 return SOFTBUS_CREATE_LIST_ERR;
230 }
231 int32_t ret = DdosHiDumperRegister();
232 if (ret != SOFTBUS_OK) {
233 LNN_LOGE(LNN_EVENT, "register ddos hidumer failed");
234 return ret;
235 }
236 RegisterClearRecordsTimer();
237 g_callRecord->cnt = 0;
238 return SOFTBUS_OK;
239 }
240
DeinitDdos(void)241 void DeinitDdos(void)
242 {
243 if (CallRecordLock() != SOFTBUS_OK) {
244 LNN_LOGE(LNN_EVENT, "CallRecord lock fail");
245 return;
246 }
247 CallRecord *next = NULL;
248 CallRecord *item = NULL;
249 LIST_FOR_EACH_ENTRY_SAFE(item, next, &g_callRecord->list, CallRecord, node) {
250 ListDelete(&item->node);
251 SoftBusFree(item);
252 }
253 CallRecordUnlock();
254 DestroySoftBusList(g_callRecord);
255 g_callRecord = NULL;
256 }