/**************************************************************************** * 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 #include #include #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 */ 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; }