1 /*
2 * Copyright (c) 2024 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 "trans_bind_request_manager.h"
17
18 #include <securec.h>
19 #include <stdlib.h>
20
21 #include "message_handler.h"
22 #include "softbus_adapter_mem.h"
23 #include "softbus_common.h"
24 #include "softbus_def.h"
25 #include "softbus_utils.h"
26 #include "trans_log.h"
27
28 #define DDOS_DETECTION_PERIOD_MS (60 * 1000) // 60s
29 #define BIND_PROTECT_PERIOD_MS (60 * 10 * 1000) // 600s
30 #define BIND_FAILED_COUNT_MAX 10
31
32 typedef enum {
33 LOOP_DELETE_TIMESTAMP,
34 LOOP_RESET_BIND_DENIED_FLAG
35 } BindRequestLoopMsg;
36
37 typedef struct {
38 ListNode node;
39 uint64_t timestamp;
40 } BindFailInfo;
41
42 typedef struct {
43 char mySocketName[SESSION_NAME_SIZE_MAX];
44 char peerSocketName[SESSION_NAME_SIZE_MAX];
45 char peerNetworkId[NETWORK_ID_BUF_LEN];
46 } BindRequestParam;
47
48 typedef struct {
49 ListNode node;
50 BindRequestParam bindRequestParam;
51 int32_t count;
52 bool bindDeniedFlag;
53 ListNode timestampList;
54 } BindRequestManager;
55
56 static SoftBusList *g_bindRequestList = NULL;
57 const char *g_transLoopName = "transBindRequestLoop";
58 static SoftBusHandler g_transLoopHandler = { 0 };
59
60 // need to get g_bindRequestList->lock before calling this function
GetBindRequestManagerByPeer(BindRequestParam * bindRequestParam)61 static BindRequestManager *GetBindRequestManagerByPeer(BindRequestParam *bindRequestParam)
62 {
63 BindRequestManager *item = NULL;
64 BindRequestManager *next = NULL;
65 LIST_FOR_EACH_ENTRY_SAFE(item, next, &g_bindRequestList->list, BindRequestManager, node) {
66 if (strcmp(item->bindRequestParam.mySocketName, bindRequestParam->mySocketName) == 0 &&
67 strcmp(item->bindRequestParam.peerSocketName, bindRequestParam->peerSocketName) == 0 &&
68 strcmp(item->bindRequestParam.peerNetworkId, bindRequestParam->peerNetworkId) == 0) {
69 return item;
70 }
71 }
72 TRANS_LOGI(TRANS_SVC, "session not found");
73 return NULL;
74 }
75
GenerateParam(const char * mySocketName,const char * peerSocketName,const char * peerNetworkId,BindRequestParam * bindReqParam)76 static int32_t GenerateParam(
77 const char *mySocketName, const char *peerSocketName, const char *peerNetworkId, BindRequestParam *bindReqParam)
78 {
79 int32_t ret = strcpy_s(bindReqParam->mySocketName, sizeof(bindReqParam->mySocketName), mySocketName);
80 TRANS_CHECK_AND_RETURN_RET_LOGE(ret == EOK, SOFTBUS_STRCPY_ERR, TRANS_SVC, "memcpy mySocketName failed");
81
82 ret = strcpy_s(bindReqParam->peerSocketName, sizeof(bindReqParam->peerSocketName), peerSocketName);
83 TRANS_CHECK_AND_RETURN_RET_LOGE(ret == EOK, SOFTBUS_STRCPY_ERR, TRANS_SVC, "memcpy peerSocketName failed");
84
85 ret = strcpy_s(bindReqParam->peerNetworkId, sizeof(bindReqParam->peerNetworkId), peerNetworkId);
86 TRANS_CHECK_AND_RETURN_RET_LOGE(ret == EOK, SOFTBUS_STRCPY_ERR, TRANS_SVC, "memcpy peerNetworkId failed");
87 return SOFTBUS_OK;
88 }
89
CreateBindRequestManager(const char * mySocketName,const char * peerSocketName,const char * peerNetworkId)90 static BindRequestManager *CreateBindRequestManager(
91 const char *mySocketName, const char *peerSocketName, const char *peerNetworkId)
92 {
93 BindRequestManager *bindRequest = (BindRequestManager *)SoftBusCalloc(sizeof(BindRequestManager));
94 TRANS_CHECK_AND_RETURN_RET_LOGE(bindRequest != NULL, NULL, TRANS_SVC, "malloc failed");
95 bindRequest->bindDeniedFlag = false;
96 bindRequest->count = 0;
97 int32_t ret = GenerateParam(mySocketName, peerSocketName, peerNetworkId, &bindRequest->bindRequestParam);
98 if (ret != SOFTBUS_OK) {
99 TRANS_LOGE(TRANS_SVC, "genarate param failed");
100 SoftBusFree(bindRequest);
101 return NULL;
102 }
103 ListInit(&bindRequest->node);
104 ListInit(&bindRequest->timestampList);
105 ListAdd(&g_bindRequestList->list, &bindRequest->node);
106 return bindRequest;
107 }
108
FreeBindRequestMessage(SoftBusMessage * msg)109 static void FreeBindRequestMessage(SoftBusMessage *msg)
110 {
111 if (msg == NULL) {
112 return;
113 }
114 if (msg->obj != NULL) {
115 SoftBusFree(msg->obj);
116 msg->obj = NULL;
117 }
118 SoftBusFree(msg);
119 }
120
TransBindRequestMsgToLooper(int32_t msgType,uint64_t param1,uint64_t param2,BindRequestParam * data,uint64_t delayMillis)121 static void TransBindRequestMsgToLooper(
122 int32_t msgType, uint64_t param1, uint64_t param2, BindRequestParam *data, uint64_t delayMillis)
123 {
124 SoftBusMessage *msg = (SoftBusMessage *)SoftBusCalloc(sizeof(SoftBusMessage));
125 TRANS_CHECK_AND_RETURN_LOGE(msg != NULL, TRANS_MSG, "msg create failed");
126 msg->what = msgType;
127 msg->arg1 = param1;
128 msg->arg2 = param2;
129 msg->handler = &g_transLoopHandler;
130
131 BindRequestParam *param = (BindRequestParam *)SoftBusCalloc(sizeof(BindRequestParam));
132 if (param == NULL) {
133 TRANS_LOGE(TRANS_SVC, "malloc failed");
134 SoftBusFree(msg);
135 return;
136 }
137 (void)GenerateParam(data->mySocketName, data->peerSocketName, data->peerNetworkId, param);
138 msg->obj = (void *)param;
139 msg->FreeMessage = FreeBindRequestMessage;
140
141 if (delayMillis == 0) {
142 g_transLoopHandler.looper->PostMessage(g_transLoopHandler.looper, msg);
143 } else {
144 g_transLoopHandler.looper->PostMessageDelay(g_transLoopHandler.looper, msg, delayMillis);
145 }
146 }
147
SendMsgToLooper(BindRequestParam * bindRequestParam,uint64_t timestamp,int32_t count)148 static void SendMsgToLooper(BindRequestParam *bindRequestParam, uint64_t timestamp, int32_t count)
149 {
150 TransBindRequestMsgToLooper(
151 LOOP_DELETE_TIMESTAMP, timestamp, 0, bindRequestParam, DDOS_DETECTION_PERIOD_MS);
152 if (count >= BIND_FAILED_COUNT_MAX) {
153 TransBindRequestMsgToLooper(
154 LOOP_RESET_BIND_DENIED_FLAG, 0, 0, bindRequestParam, BIND_PROTECT_PERIOD_MS);
155 }
156 }
157
TransAddTimestampToList(const char * mySocketName,const char * peerSocketName,const char * peerNetworkId,uint64_t timestamp)158 int32_t TransAddTimestampToList(
159 const char *mySocketName, const char *peerSocketName, const char *peerNetworkId, uint64_t timestamp)
160 {
161 if (mySocketName == NULL || peerSocketName == NULL || peerNetworkId == NULL || g_bindRequestList == NULL) {
162 return SOFTBUS_INVALID_PARAM;
163 }
164 BindRequestParam bindRequestParam = { {0} };
165 int32_t ret = GenerateParam(mySocketName, peerSocketName, peerNetworkId, &bindRequestParam);
166 TRANS_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, SOFTBUS_STRCPY_ERR, TRANS_SVC, "genarate param failed");
167 ret = SoftBusMutexLock(&g_bindRequestList->lock);
168 TRANS_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, SOFTBUS_LOCK_ERR, TRANS_SVC, "lock failed");
169
170 BindRequestManager *bindRequest = GetBindRequestManagerByPeer(&bindRequestParam);
171 if (bindRequest == NULL) {
172 bindRequest = CreateBindRequestManager(mySocketName, peerSocketName, peerNetworkId);
173 if (bindRequest == NULL) {
174 TRANS_LOGE(TRANS_SVC, "create request manager failed");
175 (void)SoftBusMutexUnlock(&g_bindRequestList->lock);
176 return SOFTBUS_MALLOC_ERR;
177 }
178 }
179 BindFailInfo *bindFailInfo = (BindFailInfo *)SoftBusCalloc(sizeof(BindFailInfo));
180 if (bindFailInfo == NULL) {
181 TRANS_LOGE(TRANS_SVC, "malloc failed");
182 (void)SoftBusMutexUnlock(&g_bindRequestList->lock);
183 return SOFTBUS_MALLOC_ERR;
184 }
185
186 bindFailInfo->timestamp = timestamp;
187 ListInit(&bindFailInfo->node);
188 ListAdd(&bindRequest->timestampList, &bindFailInfo->node);
189 bindRequest->count++;
190 int32_t count = bindRequest->count;
191 if (count >= BIND_FAILED_COUNT_MAX) {
192 bindRequest->bindDeniedFlag = true;
193 }
194 TRANS_LOGI(TRANS_SVC, "add timestamp to list success, count=%{public}d, timestamp=%{public}" PRId64,
195 count, timestamp);
196 (void)SoftBusMutexUnlock(&g_bindRequestList->lock);
197 SendMsgToLooper(&bindRequestParam, timestamp, count);
198 return SOFTBUS_OK;
199 }
200
TransDelTimestampFormList(BindRequestParam * bindRequestParam,uint64_t timestamp)201 static void TransDelTimestampFormList(BindRequestParam *bindRequestParam, uint64_t timestamp)
202 {
203 TRANS_CHECK_AND_RETURN_LOGE(g_bindRequestList != NULL, TRANS_SVC, "bind request list no init");
204 int32_t ret = SoftBusMutexLock(&g_bindRequestList->lock);
205 TRANS_CHECK_AND_RETURN_LOGE(ret == SOFTBUS_OK, TRANS_SVC, "lock bind request list failed");
206
207 BindRequestManager *bindRequest = GetBindRequestManagerByPeer(bindRequestParam);
208 if (bindRequest != NULL) {
209 BindFailInfo *failItem = NULL;
210 BindFailInfo *failNext = NULL;
211 LIST_FOR_EACH_ENTRY_SAFE(failItem, failNext, &bindRequest->timestampList, BindFailInfo, node) {
212 if (failItem->timestamp == timestamp) {
213 ListDelete(&failItem->node);
214 SoftBusFree(failItem);
215 bindRequest->count--;
216 TRANS_LOGI(TRANS_SVC, "del timestamp form list success, count=%{public}d, timestamp=%{public}" PRId64,
217 bindRequest->count, timestamp);
218 break;
219 }
220 }
221 if (bindRequest->count == 0 && !bindRequest->bindDeniedFlag) {
222 ListDelete(&bindRequest->node);
223 SoftBusFree(bindRequest);
224 }
225 }
226 (void)SoftBusMutexUnlock(&g_bindRequestList->lock);
227 }
228
GetDeniedFlagByPeer(const char * mySocketName,const char * peerSocketName,const char * peerNetworkId)229 bool GetDeniedFlagByPeer(const char *mySocketName, const char *peerSocketName, const char *peerNetworkId)
230 {
231 if (mySocketName == NULL || peerSocketName == NULL || peerNetworkId == NULL || g_bindRequestList == NULL) {
232 return false;
233 }
234
235 bool flag = false;
236 BindRequestParam bindRequestParam = { {0} };
237 int32_t ret = GenerateParam(mySocketName, peerSocketName, peerNetworkId, &bindRequestParam);
238 if (ret != SOFTBUS_OK) {
239 TRANS_LOGE(TRANS_SVC, "genarate param failed");
240 return flag;
241 }
242 ret = SoftBusMutexLock(&g_bindRequestList->lock);
243 if (ret != SOFTBUS_OK) {
244 TRANS_LOGE(TRANS_SVC, "lock bind request list failed");
245 return flag;
246 }
247
248 BindRequestManager *bindRequest = GetBindRequestManagerByPeer(&bindRequestParam);
249 if (bindRequest != NULL) {
250 flag = bindRequest->bindDeniedFlag;
251 }
252 (void)SoftBusMutexUnlock(&g_bindRequestList->lock);
253 return flag;
254 }
255
TransResetBindDeniedFlag(BindRequestParam * bindRequestParam)256 static void TransResetBindDeniedFlag(BindRequestParam *bindRequestParam)
257 {
258 TRANS_CHECK_AND_RETURN_LOGE(g_bindRequestList != NULL, TRANS_SVC, "bind request list no init");
259 int32_t ret = SoftBusMutexLock(&g_bindRequestList->lock);
260 TRANS_CHECK_AND_RETURN_LOGE(ret == SOFTBUS_OK, TRANS_SVC, "lock bind request list failed");
261
262 BindRequestManager *bindRequest = GetBindRequestManagerByPeer(bindRequestParam);
263 if (bindRequest != NULL) {
264 bindRequest->bindDeniedFlag = false;
265 ListDelete(&bindRequest->node);
266 SoftBusFree(bindRequest);
267 TRANS_LOGI(TRANS_SVC, "close bind request protect.");
268 }
269 (void)SoftBusMutexUnlock(&g_bindRequestList->lock);
270 }
271
TransBindRequestLoopMsgHandler(SoftBusMessage * msg)272 static void TransBindRequestLoopMsgHandler(SoftBusMessage *msg)
273 {
274 TRANS_LOGD(TRANS_SVC, "trans loop process msgType=%{public}d", msg->what);
275 BindRequestParam *bindRequestParam = (BindRequestParam *)msg->obj;
276 switch (msg->what) {
277 case LOOP_DELETE_TIMESTAMP: {
278 uint64_t timestamp = msg->arg1;
279 TransDelTimestampFormList(bindRequestParam, timestamp);
280 break;
281 }
282 case LOOP_RESET_BIND_DENIED_FLAG: {
283 TransResetBindDeniedFlag(bindRequestParam);
284 break;
285 }
286 default: {
287 TRANS_LOGE(TRANS_SVC, "msg type=%{public}d not support", msg->what);
288 break;
289 }
290 }
291 }
292
TransBindRequestManagerInit(void)293 int32_t TransBindRequestManagerInit(void)
294 {
295 if (g_bindRequestList != NULL) {
296 TRANS_LOGI(TRANS_INIT, "trans bind request manager has init.");
297 return SOFTBUS_OK;
298 }
299 g_bindRequestList = CreateSoftBusList();
300 if (g_bindRequestList == NULL) {
301 TRANS_LOGE(TRANS_INIT, "create bind request manager failed.");
302 return SOFTBUS_MALLOC_ERR;
303 }
304
305 g_transLoopHandler.name = (char *)g_transLoopName;
306 g_transLoopHandler.looper = GetLooper(LOOP_TYPE_DEFAULT);
307 if (g_transLoopHandler.looper == NULL) {
308 TRANS_LOGE(TRANS_INIT, "create bind request looper failed.");
309 return SOFTBUS_TRANS_INIT_FAILED;
310 }
311 g_transLoopHandler.HandleMessage = TransBindRequestLoopMsgHandler;
312 return SOFTBUS_OK;
313 }
314
TransBindRequestManagerDeinit(void)315 void TransBindRequestManagerDeinit(void)
316 {
317 if (g_bindRequestList == NULL) {
318 return;
319 }
320
321 if (SoftBusMutexLock(&g_bindRequestList->lock) != SOFTBUS_OK) {
322 TRANS_LOGE(TRANS_SVC, "lock failed");
323 return;
324 }
325 BindRequestManager *bindReqItem = NULL;
326 BindRequestManager *bindReqNext = NULL;
327 BindFailInfo *bindFailItem = NULL;
328 BindFailInfo *bindFailNext = NULL;
329 LIST_FOR_EACH_ENTRY_SAFE(bindReqItem, bindReqNext, &g_bindRequestList->list, BindRequestManager, node) {
330 LIST_FOR_EACH_ENTRY_SAFE(bindFailItem, bindFailNext, &bindReqItem->timestampList, BindFailInfo, node) {
331 ListDelete(&bindFailItem->node);
332 SoftBusFree(bindFailItem);
333 }
334 ListDelete(&bindReqItem->node);
335 SoftBusFree(bindReqItem);
336 }
337 (void)SoftBusMutexUnlock(&g_bindRequestList->lock);
338 DestroySoftBusList(g_bindRequestList);
339 g_bindRequestList = NULL;
340 g_transLoopHandler.HandleMessage = NULL;
341 g_transLoopHandler.looper = NULL;
342 }