43a8e862e0
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 <wengzhe@xiaomi.com>
290 lines
8.1 KiB
C
290 lines
8.1 KiB
C
/****************************************************************************
|
|
* 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;
|
|
}
|