This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
commit 43a8e862e0d55b4cc0b5bd71535016a9fd6b76a1 Author: Zhe Weng <[email protected]> AuthorDate: Thu Mar 21 21:11:52 2024 +0800 apps/system: Add conntrack command A simple tool like Linux's 'conntrack', only supports printing NAT connections now. nuttx> conntrack -E [NEW] icmp src=192.168.21.66 dst=1.2.3.4 type=8 code=0 id=26739 src=1.2.3.4 dst=192.168.11.1 type=0 code=0 id=26739 [NEW] tcp src=192.168.21.66 dst=1.2.3.4 sport=38446 dport=80 src=1.2.3.4 dst=192.168.11.1 sport=80 dport=38446 [DESTROY] icmp src=192.168.21.66 dst=1.2.3.4 type=8 code=0 id=26739 src=1.2.3.4 dst=192.168.11.1 type=0 code=0 id=26739 nuttx> conntrack -L tcp src=192.168.21.66 dst=1.2.3.4 sport=38446 dport=80 src=1.2.3.4 dst=192.168.11.1 sport=80 dport=38446 icmp src=192.168.21.66 dst=1.2.3.4 type=8 code=0 id=26739 src=1.2.3.4 dst=192.168.11.1 type=0 code=0 id=26739 conntrack: 2 flow entries have been shown. Signed-off-by: Zhe Weng <[email protected]> --- system/conntrack/Kconfig | 32 +++++ system/conntrack/Make.defs | 23 ++++ system/conntrack/Makefile | 30 +++++ system/conntrack/conntrack.c | 289 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 374 insertions(+) diff --git a/system/conntrack/Kconfig b/system/conntrack/Kconfig new file mode 100644 index 000000000..7c1a8ace3 --- /dev/null +++ b/system/conntrack/Kconfig @@ -0,0 +1,32 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config SYSTEM_CONNTRACK + tristate "conntrack command" + default n + depends on NETLINK_NETFILTER + select SYSTEM_ARGTABLE3 + ---help--- + Enable support for the 'conntrack' command, a simple tool like + Linux's 'conntrack', only supports printing NAT connections now. + +if SYSTEM_CONNTRACK + +config SYSTEM_CONNTRACK_PROGNAME + string "conntrack program name" + default "conntrack" + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config SYSTEM_CONNTRACK_PRIORITY + int "conntrack task priority" + default 100 + +config SYSTEM_CONNTRACK_STACKSIZE + int "conntrack stack size" + default DEFAULT_TASK_STACKSIZE + +endif diff --git a/system/conntrack/Make.defs b/system/conntrack/Make.defs new file mode 100644 index 000000000..9c746c6ad --- /dev/null +++ b/system/conntrack/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/system/conntrack/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you 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. +# +############################################################################ + +ifneq ($(CONFIG_SYSTEM_CONNTRACK),) +CONFIGURED_APPS += $(APPDIR)/system/conntrack +endif diff --git a/system/conntrack/Makefile b/system/conntrack/Makefile new file mode 100644 index 000000000..31efea8e0 --- /dev/null +++ b/system/conntrack/Makefile @@ -0,0 +1,30 @@ +############################################################################ +# apps/system/conntrack/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you 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 $(APPDIR)/Make.defs + +PROGNAME = $(CONFIG_SYSTEM_CONNTRACK_PROGNAME) +PRIORITY = $(CONFIG_SYSTEM_CONNTRACK_PRIORITY) +STACKSIZE = $(CONFIG_SYSTEM_CONNTRACK_STACKSIZE) +MODULE = $(CONFIG_SYSTEM_CONNTRACK) + +MAINSRC = conntrack.c + +include $(APPDIR)/Application.mk diff --git a/system/conntrack/conntrack.c b/system/conntrack/conntrack.c new file mode 100644 index 000000000..c58784b0d --- /dev/null +++ b/system/conntrack/conntrack.c @@ -0,0 +1,289 @@ +/**************************************************************************** + * apps/system/conntrack/conntrack.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <netpacket/netlink.h> + +#include <nuttx/net/ip.h> + +#include "argtable3.h" +#include "netutils/netlib.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define RXBUFFER_SIZE 256 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct conntrack_args_s +{ + FAR struct arg_lit *dump; + FAR struct arg_lit *event; + FAR struct arg_str *family; + FAR struct arg_end *end; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static volatile bool g_exiting; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sigexit + ****************************************************************************/ + +static void sigexit(int signo) +{ + g_exiting = true; +} + +/**************************************************************************** + * Name: proto2str + ****************************************************************************/ + +static FAR const char *proto2str(uint8_t proto) +{ + switch (proto) + { + case IPPROTO_TCP: + return "tcp"; + case IPPROTO_UDP: + return "udp"; + case IPPROTO_ICMP: + return "icmp"; + case IPPROTO_ICMP6: + return "icmp6"; + default: + return ""; + } +} + +/**************************************************************************** + * Name: conntrack_print_tuple + ****************************************************************************/ + +static void conntrack_print_tuple(sa_family_t family, + FAR const struct netlib_conntrack_tuple_s *tuple) +{ + char ipstrbuf[INET6_ADDRSTRLEN]; + + /* src=10.88.0.88 dst=192.168.66.66 sport=45065 dport=5001 */ + + inet_ntop(family, &tuple->src, ipstrbuf, INET6_ADDRSTRLEN); + printf("src=%s ", ipstrbuf); + inet_ntop(family, &tuple->dst, ipstrbuf, INET6_ADDRSTRLEN); + printf("dst=%s ", ipstrbuf); + + switch (tuple->l4proto) + { + case IPPROTO_TCP: + case IPPROTO_UDP: + printf("sport=%" PRIu16 " dport=%" PRIu16 " ", + tuple->l4.tcp.sport, tuple->l4.tcp.dport); + break; + case IPPROTO_ICMP: + case IPPROTO_ICMP6: + printf("type=%" PRIu8 " code=%" PRIu8 " id=%" PRIu16 " ", + tuple->l4.icmp.type, tuple->l4.icmp.code, tuple->l4.icmp.id); + break; + } +} + +/**************************************************************************** + * Name: conntrack_print + ****************************************************************************/ + +static int conntrack_print(FAR struct netlib_conntrack_s *ct) +{ + /* tcp <orig> <reply> */ + + printf("%-5s ", proto2str(ct->orig.l4proto)); + conntrack_print_tuple(ct->family, &ct->orig); + conntrack_print_tuple(ct->family, &ct->reply); + printf("\n"); + + return 0; +} + +/**************************************************************************** + * Name: conntrack_dump + ****************************************************************************/ + +static void conntrack_dump(sa_family_t family) +{ + ssize_t ndumped = netlib_get_conntrack(family, conntrack_print); + printf("conntrack: %zd flow entries have been shown.\n", ndumped); +} + +/**************************************************************************** + * Name: conntrack_monitor_socket + ****************************************************************************/ + +static int conntrack_monitor_socket(uint32_t groups) +{ + struct sockaddr_nl addr; + int fd; + + /* Create a NetLink socket with NETLINK_NETFILTER protocol */ + + fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_NETFILTER); + if (fd < 0) + { + perror("ERROR: failed to create netlink socket"); + return -errno; + } + + addr.nl_family = AF_NETLINK; + addr.nl_pad = 0; + addr.nl_pid = getpid(); + addr.nl_groups = groups; + + if (bind(fd, (FAR const struct sockaddr *)&addr, sizeof(addr)) < 0) + { + perror("ERROR: failed to bind netlink socket"); + close(fd); + return -errno; + } + + return fd; +} + +/**************************************************************************** + * Name: conntrack_monitor_event + ****************************************************************************/ + +static void conntrack_monitor_event(void) +{ + FAR const struct nlmsghdr *nlh; + struct netlib_conntrack_s ct; + uint8_t buf[RXBUFFER_SIZE]; + ssize_t len; + int fd; + + /* Setup exit signal handler */ + + g_exiting = false; + signal(SIGINT, sigexit); + + /* Create a NetLink socket with NETLINK_NETFILTER protocol */ + + fd = conntrack_monitor_socket(NF_NETLINK_CONNTRACK_NEW | + NF_NETLINK_CONNTRACK_DESTROY); + if (fd < 0) + { + return; + } + + while ((len = read(fd, buf, sizeof(buf))) >= 0 && !g_exiting) + { + nlh = (FAR struct nlmsghdr *)buf; + + if (netlib_parse_conntrack(nlh, len, &ct) < 0) + { + fprintf(stderr, "Failed to parse conntrack message\n"); + continue; + } + + /* Only event log needs to print type prefix */ + + switch (ct.type) + { + case IPCTNL_MSG_CT_NEW: + printf(" [NEW] "); + break; + + case IPCTNL_MSG_CT_DELETE: + printf("[DESTROY] "); + break; + + default: + printf("[UNKNOWN] "); + break; + } + + /* Print the remaining line */ + + conntrack_print(&ct); + } + + close(fd); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + struct conntrack_args_s args; + sa_family_t family = AF_INET; + int nerrors; + + args.dump = arg_lit0("L", "dump", "List connection tracking"); + args.event = arg_lit0("E", "event", "Display a real-time event log"); + args.family = arg_str0("f", "family", "PROTO", "Specify L3 (ipv4, ipv6) " + "protocol, only for dump option (default ipv4)"); + args.end = arg_end(3); + + nerrors = arg_parse(argc, argv, (FAR void **)&args); + if (nerrors != 0 || args.dump->count + args.event->count == 0) + { + arg_print_errors(stdout, args.end, argv[0]); + printf("Usage:\n"); + arg_print_glossary(stdout, (FAR void **)&args, NULL); + goto out; + } + + if (args.family->count != 0) + { + if (strncmp(args.family->sval[0], "ipv6", 4) == 0) + { + family = AF_INET6; + } + } + + if (args.dump->count != 0) + { + conntrack_dump(family); + } + + if (args.event->count != 0) + { + conntrack_monitor_event(); + } + +out: + arg_freetable((FAR void **)&args, 1); + return 0; +}
