flowctl.c revision 223788
1168404Spjd/*- 2168404Spjd * Copyright (c) 2004-2005 Gleb Smirnoff <glebius@FreeBSD.org> 3168404Spjd * Copyright (c) 2001-2003 Roman V. Palagin <romanp@unshadow.net> 4168404Spjd * All rights reserved. 5168404Spjd * 6168404Spjd * Redistribution and use in source and binary forms, with or without 7168404Spjd * modification, are permitted provided that the following conditions 8168404Spjd * are met: 9168404Spjd * 1. Redistributions of source code must retain the above copyright 10168404Spjd * notice, this list of conditions and the following disclaimer. 11168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 12168404Spjd * notice, this list of conditions and the following disclaimer in the 13168404Spjd * documentation and/or other materials provided with the distribution. 14168404Spjd * 15168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18168404Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22219089Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23263398Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24229578Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25168404Spjd * SUCH DAMAGE. 26168404Spjd * 27168404Spjd * $SourceForge: flowctl.c,v 1.15 2004/08/31 20:24:58 glebius Exp $ 28168404Spjd */ 29168404Spjd 30168404Spjd#ifndef lint 31168404Spjdstatic const char rcs_id[] = 32168404Spjd "@(#) $FreeBSD: head/usr.sbin/flowctl/flowctl.c 223788 2011-07-05 14:50:06Z glebius $"; 33168404Spjd#endif 34168404Spjd 35168404Spjd#include <sys/types.h> 36168404Spjd#include <sys/time.h> 37168404Spjd#include <sys/socket.h> 38168404Spjd#include <sys/queue.h> 39168404Spjd 40168404Spjd#include <net/if.h> 41168404Spjd#include <netinet/in.h> 42168404Spjd 43168404Spjd#include <arpa/inet.h> 44168404Spjd 45168404Spjd#include <err.h> 46168404Spjd#include <stdio.h> 47219089Spjd#include <stdlib.h> 48219089Spjd#include <string.h> 49219089Spjd#include <sysexits.h> 50168404Spjd#include <unistd.h> 51185029Spjd 52219089Spjd#include <netgraph.h> 53219089Spjd#include <netgraph/netflow/ng_netflow.h> 54168404Spjd 55249643Smm#define CISCO_SH_FLOW_HEADER "SrcIf SrcIPaddress DstIf DstIPaddress Pr SrcP DstP Pkts\n" 56168404Spjd#define CISCO_SH_FLOW "%-13s %-15s %-13s %-15s %2u %4.4x %4.4x %6lu\n" 57168404Spjd 58168404Spjd#define CISCO_SH_FLOW6_HEADER "SrcIf SrcIPaddress DstIf DstIPaddress Pr SrcP DstP Pkts\n" 59168404Spjd#define CISCO_SH_FLOW6 "%-13s %-30s %-13s %-30s %2u %4.4x %4.4x %6lu\n" 60168404Spjd 61168404Spjd#define CISCO_SH_VERB_FLOW_HEADER "SrcIf SrcIPaddress DstIf DstIPaddress Pr TOS Flgs Pkts\n" \ 62168404Spjd"Port Msk AS Port Msk AS NextHop B/Pk Active\n" 63168404Spjd 64168404Spjd#define CISCO_SH_VERB_FLOW "%-14s %-15s %-14s %-15s %2u %3x %4x %6lu\n" \ 65168404Spjd "%4.4x /%-2u %-5u %4.4x /%-2u %-5u %-15s %9u %8u\n\n" 66168404Spjd 67168404Spjd#define CISCO_SH_VERB_FLOW6_HEADER "SrcIf SrcIPaddress DstIf DstIPaddress Pr TOS Flgs Pkts\n" \ 68263398Sdelphij"Port Msk AS Port Msk AS NextHop B/Pk Active\n" 69263398Sdelphij 70263398Sdelphij#define CISCO_SH_VERB_FLOW6 "%-14s %-30s %-14s %-30s %2u %3x %4x %6lu\n" \ 71263398Sdelphij "%4.4x /%-2u %-5u %4.4x /%-2u %-5u %-30s %9u %8u\n\n" 72263398Sdelphijstatic void flow_cache_print(struct ngnf_show_header *resp); 73168404Spjdstatic void flow_cache_print6(struct ngnf_show_header *resp); 74263398Sdelphijstatic void flow_cache_print_verbose(struct ngnf_show_header *resp); 75263398Sdelphijstatic void flow_cache_print6_verbose(struct ngnf_show_header *resp); 76263398Sdelphijstatic void ctl_show(int, char **); 77263398Sdelphijstatic void do_show(int, void (*func)(struct ngnf_show_header *)); 78263398Sdelphijstatic void help(void); 79263398Sdelphijstatic void execute_command(int, char **); 80168404Spjd 81168404Spjdstruct ip_ctl_cmd { 82168404Spjd char *cmd_name; 83168404Spjd void (*cmd_func)(int argc, char **argv); 84168404Spjd}; 85263398Sdelphij 86263398Sdelphijstruct ip_ctl_cmd cmds[] = { 87263398Sdelphij {"show", ctl_show}, 88263398Sdelphij {NULL, NULL}, 89263398Sdelphij}; 90263398Sdelphij 91263398Sdelphijint cs; 92263398Sdelphijchar *ng_path; 93263398Sdelphij 94263398Sdelphijint 95168404Spjdmain(int argc, char **argv) 96168404Spjd{ 97168404Spjd int c; 98168404Spjd char sname[NG_NODESIZ]; 99168404Spjd int rcvbuf = SORCVBUF_SIZE; 100168404Spjd 101168404Spjd /* parse options */ 102168404Spjd while ((c = getopt(argc, argv, "d:")) != -1) { 103168404Spjd switch (c) { 104168404Spjd case 'd': /* set libnetgraph debug level. */ 105168404Spjd NgSetDebug(atoi(optarg)); 106168404Spjd break; 107168404Spjd } 108168404Spjd } 109266123Ssmh 110262081Savg argc -= optind; 111262081Savg argv += optind; 112262081Savg ng_path = argv[0]; 113262081Savg if (ng_path == NULL || (strlen(ng_path) > NG_PATHSIZ)) 114262081Savg help(); 115262081Savg argc--; 116262081Savg argv++; 117262081Savg 118262081Savg /* create control socket. */ 119262081Savg snprintf(sname, sizeof(sname), "flowctl%i", getpid()); 120266123Ssmh 121266123Ssmh if (NgMkSockNode(sname, &cs, NULL) == -1) 122266123Ssmh err(1, "NgMkSockNode"); 123266123Ssmh 124266123Ssmh /* set receive buffer size */ 125185029Spjd if (setsockopt(cs, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) == -1) 126185029Spjd err(1, "setsockopt(SOL_SOCKET, SO_RCVBUF)"); 127243674Smm 128185029Spjd /* parse and execute command */ 129185029Spjd execute_command(argc, argv); 130168404Spjd 131168404Spjd close(cs); 132168404Spjd 133168404Spjd exit(0); 134168404Spjd} 135168404Spjd 136168404Spjdstatic void 137168404Spjdexecute_command(int argc, char **argv) 138168404Spjd{ 139168404Spjd int cindex = -1; 140168404Spjd int i; 141168404Spjd 142168404Spjd if (!argc) 143168404Spjd help(); 144168404Spjd for (i = 0; cmds[i].cmd_name != NULL; i++) 145168404Spjd if (!strncmp(argv[0], cmds[i].cmd_name, strlen(argv[0]))) { 146168404Spjd if (cindex != -1) 147168404Spjd errx(1, "ambiguous command: %s", argv[0]); 148168404Spjd cindex = i; 149168404Spjd } 150168404Spjd if (cindex == -1) 151168404Spjd errx(1, "bad command: %s", argv[0]); 152168404Spjd argc--; 153168404Spjd argv++; 154168404Spjd (*cmds[cindex].cmd_func)(argc, argv); 155168404Spjd} 156168404Spjd 157168404Spjdstatic void 158168404Spjdctl_show(int argc, char **argv) 159168404Spjd{ 160168404Spjd int ipv4 = 1, ipv6 = 1, verbose = 0; 161168404Spjd 162168404Spjd if (argc > 0 && !strncmp(argv[0], "ipv4", 4)) { 163168404Spjd ipv6 = 0; 164168404Spjd argc--; 165168404Spjd argv++; 166168404Spjd } 167168404Spjd if (argc > 0 && !strncmp(argv[0], "ipv6", 4)) { 168168404Spjd ipv4 = 0; 169168404Spjd argc--; 170168404Spjd argv++; 171168404Spjd } 172168404Spjd 173219089Spjd if (argc > 0 && !strncmp(argv[0], "verbose", strlen(argv[0]))) 174168404Spjd verbose = 1; 175168404Spjd 176168404Spjd if (ipv4) { 177168404Spjd if (verbose) 178168404Spjd do_show(4, &flow_cache_print_verbose); 179219089Spjd else 180168404Spjd do_show(4, &flow_cache_print); 181219089Spjd } 182168404Spjd 183168404Spjd if (ipv6) { 184168404Spjd if (verbose) 185168404Spjd do_show(6, &flow_cache_print6_verbose); 186168404Spjd else 187168404Spjd do_show(6, &flow_cache_print6); 188168404Spjd } 189168404Spjd} 190168404Spjd 191168404Spjdstatic void 192168404Spjddo_show(int version, void (*func)(struct ngnf_show_header *)) 193168404Spjd{ 194168404Spjd struct ng_mesg *ng_mesg; 195168404Spjd struct ngnf_show_header req, *resp; 196168404Spjd int token, nread; 197168404Spjd 198168404Spjd ng_mesg = alloca(SORCVBUF_SIZE); 199168404Spjd 200168404Spjd req.version = version; 201168404Spjd req.hash_id = req.list_id = 0; 202168404Spjd 203168404Spjd for (;;) { 204168404Spjd /* request set of accounting records */ 205219089Spjd token = NgSendMsg(cs, ng_path, NGM_NETFLOW_COOKIE, 206219089Spjd NGM_NETFLOW_SHOW, (void *)&req, sizeof(req)); 207219089Spjd if (token == -1) 208219089Spjd err(1, "NgSendMsg(NGM_NETFLOW_SHOW)"); 209168404Spjd 210219089Spjd /* read reply */ 211219089Spjd nread = NgRecvMsg(cs, ng_mesg, SORCVBUF_SIZE, NULL); 212168404Spjd if (nread == -1) 213168404Spjd err(1, "NgRecvMsg() failed"); 214168404Spjd 215219089Spjd if (ng_mesg->header.token != token) 216219089Spjd err(1, "NgRecvMsg(NGM_NETFLOW_SHOW): token mismatch"); 217219089Spjd 218263398Sdelphij resp = (struct ngnf_show_header *)ng_mesg->data; 219263398Sdelphij if ((ng_mesg->header.arglen < (sizeof(*resp))) || 220263398Sdelphij (ng_mesg->header.arglen < (sizeof(*resp) + 221263398Sdelphij (resp->nentries * sizeof(struct flow_entry_data))))) 222263398Sdelphij err(1, "NgRecvMsg(NGM_NETFLOW_SHOW): arglen too small"); 223263398Sdelphij 224263398Sdelphij (*func)(resp); 225263398Sdelphij 226263398Sdelphij if (resp->hash_id != 0) 227168404Spjd req.hash_id = resp->hash_id; 228219089Spjd else 229219089Spjd break; 230219089Spjd req.list_id = resp->list_id; 231219089Spjd } 232219089Spjd} 233219089Spjd 234219089Spjdstatic void 235168404Spjdflow_cache_print(struct ngnf_show_header *resp) 236168404Spjd{ 237168404Spjd struct flow_entry_data *fle; 238168404Spjd char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN]; 239168404Spjd char src_if[IFNAMSIZ], dst_if[IFNAMSIZ]; 240168404Spjd int i; 241263398Sdelphij 242168404Spjd if (resp->version != 4) 243263398Sdelphij errx(EX_SOFTWARE, "%s: version mismatch: %u", 244263398Sdelphij __func__, resp->version); 245168404Spjd 246168404Spjd printf(CISCO_SH_FLOW_HEADER); 247168404Spjd 248168404Spjd fle = (struct flow_entry_data *)(resp + 1); 249168404Spjd for (i = 0; i < resp->nentries; i++, fle++) { 250168404Spjd inet_ntop(AF_INET, &fle->r.r_src, src, sizeof(src)); 251168404Spjd inet_ntop(AF_INET, &fle->r.r_dst, dst, sizeof(dst)); 252168404Spjd printf(CISCO_SH_FLOW, 253168404Spjd if_indextoname(fle->fle_i_ifx, src_if), 254168404Spjd src, 255168404Spjd if_indextoname(fle->fle_o_ifx, dst_if), 256168404Spjd dst, 257168404Spjd fle->r.r_ip_p, 258168404Spjd ntohs(fle->r.r_sport), 259168404Spjd ntohs(fle->r.r_dport), 260168404Spjd fle->packets); 261263398Sdelphij 262168404Spjd } 263263398Sdelphij} 264168404Spjd 265168404Spjd#ifdef INET6 266263398Sdelphijstatic void 267168404Spjdflow_cache_print6(struct ngnf_show_header *resp) 268263398Sdelphij{ 269168404Spjd struct flow6_entry_data *fle6; 270219089Spjd char src6[INET6_ADDRSTRLEN], dst6[INET6_ADDRSTRLEN]; 271219089Spjd char src_if[IFNAMSIZ], dst_if[IFNAMSIZ]; 272168404Spjd int i; 273219089Spjd 274219089Spjd if (resp->version != 6) 275168404Spjd errx(EX_SOFTWARE, "%s: version mismatch: %u", 276219089Spjd __func__, resp->version); 277219089Spjd 278168404Spjd printf(CISCO_SH_FLOW6_HEADER); 279219089Spjd 280219089Spjd fle6 = (struct flow6_entry_data *)(resp + 1); 281168404Spjd for (i = 0; i < resp->nentries; i++, fle6++) { 282219089Spjd inet_ntop(AF_INET6, &fle6->r.src.r_src6, src6, sizeof(src6)); 283219089Spjd inet_ntop(AF_INET6, &fle6->r.dst.r_dst6, dst6, sizeof(dst6)); 284168404Spjd printf(CISCO_SH_FLOW6, 285219089Spjd if_indextoname(fle6->fle_i_ifx, src_if), 286219089Spjd src6, 287219089Spjd if_indextoname(fle6->fle_o_ifx, dst_if), 288263398Sdelphij dst6, 289219089Spjd fle6->r.r_ip_p, 290219089Spjd ntohs(fle6->r.r_sport), 291219089Spjd ntohs(fle6->r.r_dport), 292219089Spjd fle6->packets); 293219089Spjd 294219089Spjd } 295219089Spjd} 296219089Spjd#endif 297219089Spjd 298219089Spjdstatic void 299219089Spjdflow_cache_print_verbose(struct ngnf_show_header *resp) 300168404Spjd{ 301168404Spjd struct flow_entry_data *fle; 302168404Spjd char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN], next[INET_ADDRSTRLEN]; 303168404Spjd char src_if[IFNAMSIZ], dst_if[IFNAMSIZ]; 304168404Spjd int i; 305243674Smm 306219089Spjd if (resp->version != 4) 307168404Spjd errx(EX_SOFTWARE, "%s: version mismatch: %u", 308168404Spjd __func__, resp->version); 309168404Spjd 310168404Spjd printf(CISCO_SH_VERB_FLOW_HEADER); 311168404Spjd 312168404Spjd fle = (struct flow_entry_data *)(resp + 1); 313168404Spjd for (i = 0; i < resp->nentries; i++, fle++) { 314168404Spjd inet_ntop(AF_INET, &fle->r.r_src, src, sizeof(src)); 315168404Spjd inet_ntop(AF_INET, &fle->r.r_dst, dst, sizeof(dst)); 316168404Spjd inet_ntop(AF_INET, &fle->next_hop, next, sizeof(next)); 317168404Spjd printf(CISCO_SH_VERB_FLOW, 318168404Spjd if_indextoname(fle->fle_i_ifx, src_if), 319168404Spjd src, 320168404Spjd if_indextoname(fle->fle_o_ifx, dst_if), 321168404Spjd dst, 322219089Spjd fle->r.r_ip_p, 323219089Spjd fle->r.r_tos, 324219089Spjd fle->tcp_flags, 325219089Spjd fle->packets, 326219089Spjd ntohs(fle->r.r_sport), 327219089Spjd fle->src_mask, 328168404Spjd 0, 329168404Spjd ntohs(fle->r.r_dport), 330168404Spjd fle->dst_mask, 331168404Spjd 0, 332168404Spjd next, 333168404Spjd (u_int)(fle->bytes / fle->packets), 334168404Spjd 0); 335168404Spjd 336168404Spjd } 337168404Spjd} 338168404Spjd 339168404Spjd#ifdef INET6 340168404Spjdstatic void 341168404Spjdflow_cache_print6_verbose(struct ngnf_show_header *resp) 342168404Spjd{ 343168404Spjd struct flow6_entry_data *fle6; 344168404Spjd char src6[INET6_ADDRSTRLEN], dst6[INET6_ADDRSTRLEN], next6[INET6_ADDRSTRLEN]; 345168404Spjd char src_if[IFNAMSIZ], dst_if[IFNAMSIZ]; 346263398Sdelphij int i; 347263398Sdelphij 348263398Sdelphij if (resp->version != 6) 349168404Spjd errx(EX_SOFTWARE, "%s: version mismatch: %u", 350219089Spjd __func__, resp->version); 351219089Spjd 352219089Spjd printf(CISCO_SH_VERB_FLOW6_HEADER); 353219089Spjd 354168404Spjd fle6 = (struct flow6_entry_data *)(resp + 1); 355168404Spjd for (i = 0; i < resp->nentries; i++, fle6++) { 356168404Spjd inet_ntop(AF_INET6, &fle6->r.src.r_src6, src6, sizeof(src6)); 357168404Spjd inet_ntop(AF_INET6, &fle6->r.dst.r_dst6, dst6, sizeof(dst6)); 358168404Spjd inet_ntop(AF_INET6, &fle6->n.next_hop6, next6, sizeof(next6)); 359168404Spjd printf(CISCO_SH_VERB_FLOW6, 360168404Spjd if_indextoname(fle6->fle_i_ifx, src_if), 361168404Spjd src6, 362168404Spjd if_indextoname(fle6->fle_o_ifx, dst_if), 363168404Spjd dst6, 364168404Spjd fle6->r.r_ip_p, 365219089Spjd fle6->r.r_tos, 366168404Spjd fle6->tcp_flags, 367168404Spjd fle6->packets, 368168404Spjd ntohs(fle6->r.r_sport), 369168404Spjd fle6->src_mask, 370168404Spjd 0, 371174049Sjb ntohs(fle6->r.r_dport), 372168404Spjd fle6->dst_mask, 373168404Spjd 0, 374263398Sdelphij next6, 375168404Spjd (u_int)(fle6->bytes / fle6->packets), 376168404Spjd 0); 377168404Spjd } 378168404Spjd} 379168404Spjd#endif 380168404Spjd 381219089Spjdstatic void 382219089Spjdhelp(void) 383219089Spjd{ 384219089Spjd extern char *__progname; 385219089Spjd 386263398Sdelphij fprintf(stderr, "usage: %s [-d level] nodename command\n", __progname); 387219089Spjd exit (0); 388219089Spjd} 389219089Spjd