summaryrefslogtreecommitdiffstats
path: root/stacks/lwip_stack/src/tools/dump_tool.c
diff options
context:
space:
mode:
Diffstat (limited to 'stacks/lwip_stack/src/tools/dump_tool.c')
-rw-r--r--stacks/lwip_stack/src/tools/dump_tool.c611
1 files changed, 611 insertions, 0 deletions
diff --git a/stacks/lwip_stack/src/tools/dump_tool.c b/stacks/lwip_stack/src/tools/dump_tool.c
new file mode 100644
index 0000000..7e6e67c
--- /dev/null
+++ b/stacks/lwip_stack/src/tools/dump_tool.c
@@ -0,0 +1,611 @@
+/*
+*
+* Copyright (c) 2018 Huawei Technologies Co.,Ltd.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at:
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <arpa/inet.h>
+
+#include "nsfw_init_api.h"
+#include "nsfw_maintain_api.h"
+#include "nsfw_mem_api.h"
+#include "nsfw_fd_timer_api.h"
+#include "nstack_log.h"
+#include "nstack_securec.h"
+
+#include "dump_tool.h"
+#include "nstack_dmm_adpt.h"
+
+NSTACK_STATIC u32 g_dump_task_mask = 0;
+NSTACK_STATIC dump_task_info g_dump_task[MAX_DUMP_TASK];
+static dump_timer_info g_dump_timer;
+
+static nsfw_mem_name g_dump_mem_ring_info =
+ { NSFW_SHMEM, NSFW_PROC_MAIN, DUMP_SHMEM_RING_NAME };
+static nsfw_mem_name g_dump_mem_pool_info =
+ { NSFW_SHMEM, NSFW_PROC_MAIN, DUMP_SHMEM_POOL_NAME };
+
+NSTACK_STATIC inline void dump_task_init(dump_task_info * task)
+{
+ task->task_state = 0;
+ task->task_id = -1;
+ task->task_keep_time = 0;
+ task->task_pool = NULL;
+ task->task_queue = NULL;
+}
+
+NSTACK_STATIC inline void clear_dump_task()
+{
+ int i = 0;
+ for (; i < MAX_DUMP_TASK; i++)
+ {
+ dump_task_init(&g_dump_task[i]);
+ }
+}
+
+NSTACK_STATIC i16 get_dump_task(nsfw_tool_dump_msg * req)
+{
+ // base version just support 1 dump task
+ if (req->task_keep_time > MAX_DUMP_TIME
+ || req->task_keep_time < MIN_DUMP_TIME)
+ {
+ NSPOL_DUMP_LOGERR("task keep time invalid] time=%u.",
+ req->task_keep_time);
+ return -1;
+ }
+
+ if (1 == g_dump_task[0].task_state)
+ {
+ NSPOL_DUMP_LOGERR
+ ("start tcpdump task failed, task still in work state] task id=%d.",
+ 0);
+ return -1;
+ }
+
+ struct timespec cur_time;
+ GET_CUR_TIME(&cur_time); /*do not need return value */
+ g_dump_task[0].task_start_sec = cur_time.tv_sec;
+ g_dump_task[0].last_hbt_sec = cur_time.tv_sec;
+
+ g_dump_task[0].task_state = 1;
+ g_dump_task[0].task_id = 0;
+ g_dump_task[0].task_keep_time = req->task_keep_time;
+
+ g_dump_task_mask |= (1 << g_dump_task[0].task_id);
+ NSPOL_DUMP_LOGINF("start tcpdump task success] task id=%d.", 0);
+ return 0;
+}
+
+NSTACK_STATIC i16 close_dump_task(i16 task_id)
+{
+ if (task_id < 0 || task_id >= MAX_DUMP_TASK)
+ {
+ NSPOL_DUMP_LOGERR
+ ("receive invalid task id in close dump task req] task id=%d.",
+ task_id);
+ return -1;
+ }
+
+ g_dump_task[task_id].task_state = 0;
+
+ g_dump_task_mask &= ~(1 << task_id);
+
+ NSPOL_DUMP_LOGINF("stop tcpdump task success] task id=%d.", 0);
+
+ return task_id;
+}
+
+NSTACK_STATIC void stop_expired_task(int idx, u32 now_sec)
+{
+ dump_task_info *ptask = &g_dump_task[idx];
+ if (0 == ptask->task_state)
+ {
+ return;
+ }
+
+ if (now_sec - ptask->task_start_sec > ptask->task_keep_time)
+ {
+ NSPOL_DUMP_LOGERR
+ ("stop dump task because task time expired] task id=%d, now_sec=%u, task start time=%u, dump time=%u.",
+ ptask->task_id, now_sec, ptask->task_start_sec,
+ ptask->task_keep_time);
+ close_dump_task(ptask->task_id);
+ return;
+ }
+
+ if (now_sec - ptask->last_hbt_sec > DUMP_TASK_HBT_TIME_OUT)
+ {
+ NSPOL_DUMP_LOGERR
+ ("stop dump task because heart beat time out] task id=%d, now_sec=%u, last hbt time=%u, hbt timeout=%u.",
+ ptask->task_id, now_sec, ptask->last_hbt_sec,
+ DUMP_TASK_HBT_TIME_OUT);
+ close_dump_task(ptask->task_id);
+ }
+
+ return;
+}
+
+NSTACK_STATIC inline bool check_dump_alive(u32 timer_type, void *data)
+{
+ dump_timer_info *ptimer_info = (dump_timer_info *) data;
+
+ struct timespec cur_time;
+ GET_CUR_TIME(&cur_time); /*do not need return value */
+
+ int i = 0;
+ for (; i < MAX_DUMP_TASK; i++)
+ {
+ stop_expired_task(i, cur_time.tv_sec);
+ }
+
+ ptimer_info->ptimer =
+ nsfw_timer_reg_timer(1, ptimer_info, check_dump_alive,
+ *(struct timespec *) (ptimer_info->interval));
+
+ return true;
+}
+
+NSTACK_STATIC bool dump_init_timer(dump_timer_info * ptimer_info)
+{
+ struct timespec *trigger_time =
+ (struct timespec *) malloc(sizeof(struct timespec));
+ if (NULL == trigger_time)
+ {
+ NSPOL_DUMP_LOGERR("alloc memory for timer failed.");
+ return false;
+ }
+
+ trigger_time->tv_sec = DUMP_HBT_CHK_INTERVAL;
+ trigger_time->tv_nsec = 0;
+
+ ptimer_info->interval = trigger_time;
+ ptimer_info->ptimer =
+ nsfw_timer_reg_timer(1, ptimer_info, check_dump_alive, *trigger_time);
+ return true;
+}
+
+NSTACK_STATIC inline u32
+copy_limit_buf(char *dst_buf, int dst_buf_len, char *src_buf,
+ u32 src_buf_len, u32 limit_len)
+{
+ if (src_buf_len < limit_len)
+ {
+ NSPOL_DUMP_LOGERR("message too short] len=%d", src_buf_len);
+ return 0;
+ }
+
+ if (EOK != memcpy_s(dst_buf, dst_buf_len, src_buf, limit_len))
+ {
+ NSPOL_DUMP_LOGERR("MEMCPY_S failed");
+ return 0;
+ }
+
+ return limit_len;
+}
+
+NSTACK_STATIC inline u32
+get_packet_buf(char *dst_buf, int dst_buf_len, char *src_buf,
+ u32 src_buf_len, u32 eth_head_len)
+{
+#define TCP_BUF_LEN (eth_head_len + IP_HEAD_LEN + TCP_HEAD_LEN)
+#define UDP_BUF_LEN (eth_head_len + IP_HEAD_LEN + UDP_HEAD_LEN)
+#define ICMP_BUF_LEN (eth_head_len + IP_HEAD_LEN + ICMP_HEAD_LEN)
+
+ if (NULL == dst_buf || NULL == src_buf)
+ {
+ return 0;
+ }
+
+ struct ip_hdr *ip_head = (struct ip_hdr *) (src_buf + eth_head_len);
+ if (ip_head->_proto == IP_PROTO_TCP)
+ {
+ return copy_limit_buf(dst_buf, dst_buf_len, src_buf, src_buf_len,
+ TCP_BUF_LEN);
+ }
+
+ if (ip_head->_proto == IP_PROTO_UDP)
+ {
+ return copy_limit_buf(dst_buf, dst_buf_len, src_buf, src_buf_len,
+ UDP_BUF_LEN);
+ }
+
+ if (ip_head->_proto == IP_PROTO_ICMP)
+ {
+ return copy_limit_buf(dst_buf, dst_buf_len, src_buf, src_buf_len,
+ ICMP_BUF_LEN);
+ }
+
+ if (EOK != memcpy_s(dst_buf, dst_buf_len, src_buf, src_buf_len))
+ {
+ NSPOL_DUMP_LOGERR("MEMCPY_S failed");
+ return 0;
+ }
+
+ return src_buf_len;
+}
+
+NSTACK_STATIC int
+pack_msg_inout(void *dump_buf, char *msg_buf, u32 len, u16 direction,
+ void *para)
+{
+ (void) para;
+ dump_msg_info *pmsg = (dump_msg_info *) dump_buf;
+ if (!pmsg)
+ {
+ return 0;
+ }
+
+ pmsg->direction = direction;
+ struct timeval cur_time;
+ gettimeofday(&cur_time, NULL);
+ pmsg->dump_sec = cur_time.tv_sec;
+ pmsg->dump_usec = cur_time.tv_usec;
+
+ /* msg content can not be captured */
+ u32 real_len =
+ get_packet_buf(pmsg->buf, DUMP_MSG_SIZE, msg_buf, len, ETH_HEAD_LEN);
+ if (0 == real_len)
+ {
+ return 0;
+ }
+
+ pmsg->len = real_len;
+
+ return 1;
+}
+
+NSTACK_STATIC int
+pack_msg_loop(void *dump_buf, char *msg_buf, u32 len, u16 direction,
+ void *para)
+{
+ dump_msg_info *pmsg = (dump_msg_info *) dump_buf;
+ if (!pmsg)
+ {
+ return 0;
+ }
+ pmsg->direction = direction;
+ struct timeval cur_time;
+ gettimeofday(&cur_time, NULL);
+ pmsg->dump_sec = cur_time.tv_sec;
+ pmsg->dump_usec = cur_time.tv_usec;
+
+ eth_head pack_eth_head;
+ int retVal =
+ memcpy_s(pack_eth_head.dest_mac, MAC_ADDR_LEN, para, MAC_ADDR_LEN);
+ if (EOK != retVal)
+ {
+ NSPOL_DUMP_LOGERR("MEMCPY_S failed]retVal=%d", retVal);
+ return 0;
+ }
+ retVal =
+ memcpy_s(pack_eth_head.src_mac, MAC_ADDR_LEN, para, MAC_ADDR_LEN);
+ if (EOK != retVal)
+ {
+ NSPOL_DUMP_LOGERR("MEMCPY_S failed]retVal=%d", retVal);
+ return 0;
+ }
+ pack_eth_head.eth_type = htons(PROTOCOL_IP);
+
+ retVal =
+ memcpy_s(pmsg->buf, DUMP_MSG_SIZE, &pack_eth_head, sizeof(eth_head));
+ if (EOK != retVal)
+ {
+ NSPOL_DUMP_LOGERR("MEMCPY_S failed]retVal=%d", retVal);
+ return 0;
+ }
+
+ u32 buf_len = DUMP_MSG_SIZE - ETH_HEAD_LEN;
+
+ /* msg content can not be captured- Begin */
+ u32 real_len =
+ get_packet_buf(pmsg->buf + ETH_HEAD_LEN, buf_len, msg_buf, len, 0);
+ if (0 == real_len)
+ {
+ return 0;
+ }
+
+ pmsg->len = real_len + ETH_HEAD_LEN;
+
+ return 1;
+}
+
+NSTACK_STATIC void
+dump_enqueue(int task_idx, void *buf, u32 len, u16 direction,
+ pack_msg_fun pack_msg, void *para)
+{
+ mring_handle queue = (mring_handle *) g_dump_task[task_idx].task_queue;
+ mring_handle pool = (mring_handle *) g_dump_task[task_idx].task_pool;
+
+ void *msg = NULL;
+
+ if (nsfw_mem_ring_dequeue(pool, &msg) <= 0)
+ {
+ // such log may be too much if queue is empty
+ NSPOL_DUMP_LOGDBG("get msg node from mem pool failed] pool=%p.",
+ pool);
+ return;
+ }
+
+ if (NULL == msg)
+ {
+ NSPOL_DUMP_LOGWAR("get NULL msg node from mem pool] pool=%p.", pool);
+ return;
+ }
+
+ if (!pack_msg(msg, buf, len, direction, para))
+ {
+ NSPOL_DUMP_LOGWAR("get dump msg failed");
+ return;
+ }
+
+ if (nsfw_mem_ring_enqueue(queue, msg) < 0)
+ {
+ NSPOL_DUMP_LOGWAR("dump mem ring enqueue failed] ring=%p.", queue);
+ }
+
+ return;
+}
+
+NSTACK_STATIC inline bool dump_enabled()
+{
+ return (0 != g_dump_task_mask);
+}
+
+void ntcpdump(void *buf, u32 buf_len, u16 direction)
+{
+ u32 i;
+ if (!dump_enabled())
+ {
+ return;
+ }
+
+ /* fix Dead-code type Codedex issue here */
+ for (i = 0; i < MAX_DUMP_TASK; i++)
+ {
+ if (g_dump_task[i].task_state)
+ {
+ dump_enqueue(i, buf, buf_len, direction, pack_msg_inout, NULL);
+ }
+ }
+}
+
+void ntcpdump_loop(void *buf, u32 buf_len, u16 direction, void *eth_addr)
+{
+ u32 i;
+
+ if (!dump_enabled())
+ {
+ return;
+ }
+
+ /* fix Dead-code type Codedex issue here */
+ for (i = 0; i < MAX_DUMP_TASK; i++)
+ {
+ if (g_dump_task[i].task_state)
+ {
+ dump_enqueue(i, buf, buf_len, direction, pack_msg_loop, eth_addr);
+ }
+ }
+}
+
+// called by nStackMain
+bool dump_create_pool()
+{
+ nsfw_mem_sppool pool_info;
+ if (EOK !=
+ memcpy_s(&pool_info.stname, sizeof(nsfw_mem_name),
+ &g_dump_mem_pool_info, sizeof(nsfw_mem_name)))
+ {
+ NSPOL_DUMP_LOGERR("create dump mem pool failed, MEMCPY_S failed.");
+ return false;
+ }
+
+ pool_info.usnum = MAX_DUMP_MSG_NUM;
+ pool_info.useltsize = DUMP_MSG_SIZE + sizeof(dump_msg_info);
+ pool_info.isocket_id = NSFW_SOCKET_ANY;
+ pool_info.enmptype = NSFW_MRING_MPSC;
+
+ mring_handle pool = nsfw_mem_sp_create(&pool_info);
+ if (NULL == pool)
+ {
+ NSPOL_DUMP_LOGERR("create dump mem pool failed, pool create failed.");
+ return false;
+ }
+
+ g_dump_task[0].task_pool = pool;
+
+ NSPOL_DUMP_LOGINF("dump pool create success] pool=%p.", pool);
+
+ return true;
+}
+
+bool dump_create_ring()
+{
+ nsfw_mem_mring ring_info;
+ if (EOK !=
+ memcpy_s(&ring_info.stname, sizeof(nsfw_mem_name),
+ &g_dump_mem_ring_info, sizeof(nsfw_mem_name)))
+ {
+ NSPOL_DUMP_LOGERR("create dump mem ring failed, MEMCPY_S failed.");
+ return false;
+ }
+
+ ring_info.usnum = MAX_DUMP_MSG_NUM;
+ ring_info.isocket_id = NSFW_SOCKET_ANY;
+ ring_info.enmptype = NSFW_MRING_MPSC;
+
+ mring_handle ring = nsfw_mem_ring_create(&ring_info);
+ if (NULL == ring)
+ {
+ NSPOL_DUMP_LOGERR("create dump mem ring failed, ring create failed.");
+ return false;
+ }
+
+ g_dump_task[0].task_queue = ring;
+
+ NSPOL_DUMP_LOGINF("dump ring create success] ring=%p.", ring);
+
+ return true;
+}
+
+NSTACK_STATIC int on_dump_tool_req(nsfw_mgr_msg * req)
+{
+ i16 task_id = 0;
+ if (!req)
+ {
+ return -1;
+ }
+ if (req->src_proc_type != NSFW_PROC_TOOLS)
+ {
+ NSPOL_DUMP_LOGDBG
+ ("dump module receive invaild message] module type=%u.",
+ req->src_proc_type);
+ return -1;
+ }
+
+ if (req->msg_type != MGR_MSG_TOOL_TCPDUMP_REQ)
+ {
+ NSPOL_DUMP_LOGDBG("dump module receive invaild message] msg type=%u.",
+ req->msg_type);
+ return -1;
+ }
+
+ nsfw_tool_dump_msg *dump_msg_req = GET_USER_MSG(nsfw_tool_dump_msg, req);
+
+ switch (dump_msg_req->op_type)
+ {
+ case START_DUMP_REQ:
+ task_id = get_dump_task(dump_msg_req);
+ break;
+
+ case STOP_DUMP_REQ:
+ task_id = close_dump_task(dump_msg_req->task_id);
+ break;
+
+ default:
+ task_id = -1;
+ }
+
+ nsfw_mgr_msg *rsp = nsfw_mgr_rsp_msg_alloc(req);
+ if (NULL == rsp)
+ {
+ NSPOL_DUMP_LOGDBG("alloc response for dump request failed.");
+ return -1;
+ }
+
+ nsfw_tool_dump_msg *dump_msg_rsp = GET_USER_MSG(nsfw_tool_dump_msg, rsp);
+ dump_msg_rsp->op_type = dump_msg_req->op_type + DUMP_MSG_TYPE_RSP;
+ dump_msg_rsp->task_id = task_id;
+
+ nsfw_mgr_send_msg(rsp);
+ nsfw_mgr_msg_free(rsp);
+ return 0;
+
+}
+
+NSTACK_STATIC int on_dump_hbt_req(nsfw_mgr_msg * req)
+{
+ if (!req)
+ {
+ return -1;
+ }
+ if (req->src_proc_type != NSFW_PROC_TOOLS)
+ {
+ NSPOL_DUMP_LOGDBG
+ ("dump module receive invaild message] module type=%u.",
+ req->src_proc_type);
+ return -1;
+ }
+
+ if (req->msg_type != MGR_MSG_TOOL_HEART_BEAT)
+ {
+ NSPOL_DUMP_LOGDBG("dump module receive invaild message] msg type=%u.",
+ req->msg_type);
+ return -1;
+ }
+
+ nsfw_tool_hbt *dump_hbt_req = GET_USER_MSG(nsfw_tool_hbt, req);
+
+ i16 task_id = dump_hbt_req->task_id;
+ if (task_id < 0 || task_id >= MAX_DUMP_TASK)
+ {
+ NSPOL_DUMP_LOGERR("dump heart beat with invalid task id] task id=%d.",
+ task_id);
+ return -1;
+ }
+
+ if (0 == g_dump_task[task_id].task_state)
+ {
+ NSPOL_DUMP_LOGDBG
+ ("dump module receive heart beat but task not enabled] task id=%d.",
+ task_id);
+ return 0;
+ }
+
+ struct timespec cur_time;
+ GET_CUR_TIME(&cur_time); /*no need return value */
+
+ // update task alive time
+ g_dump_task[task_id].last_hbt_seq = dump_hbt_req->seq;
+ g_dump_task[task_id].last_hbt_sec = cur_time.tv_sec;
+
+ return 0;
+}
+
+NSTACK_STATIC int dump_tool_init(void *param);
+NSTACK_STATIC int dump_tool_init(void *param)
+{
+ u32 proc_type = (u32) ((long long) param);
+ NSPOL_DUMP_LOGINF("dump module init] proc type=%d", proc_type);
+
+ switch (proc_type)
+ {
+ case NSFW_PROC_MAIN:
+ nsfw_mgr_reg_msg_fun(MGR_MSG_TOOL_TCPDUMP_REQ, on_dump_tool_req);
+ nsfw_mgr_reg_msg_fun(MGR_MSG_TOOL_HEART_BEAT, on_dump_hbt_req);
+ break;
+ default:
+ NSPOL_DUMP_LOGERR("dump init with unknow module] proc type=%d",
+ proc_type);
+ return -1;
+ }
+
+ clear_dump_task();
+
+ if (!dump_create_ring())
+ {
+ return -1;
+ }
+
+ if (!dump_create_pool())
+ {
+ return -1;
+ }
+
+ if (!dump_init_timer(&g_dump_timer))
+ {
+ return -1;
+ }
+
+ NSPOL_DUMP_LOGINF("dump module init success.");
+ return 0;
+}
+
+/* *INDENT-OFF* */
+NSFW_MODULE_NAME (TCPDUMP_MODULE)
+NSFW_MODULE_PRIORITY (10)
+NSFW_MODULE_DEPENDS(NSFW_MEM_MGR_MODULE)
+NSFW_MODULE_DEPENDS(NSFW_MGR_COM_MODULE)
+NSFW_MODULE_DEPENDS(NSFW_TIMER_MODULE)
+NSFW_MODULE_INIT (dump_tool_init)
+/* *INDENT-ON* */