• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }