flowctl.c revision 135400
1/*- 2 * Copyright (c) 2004 Gleb Smirnoff <glebius@FreeBSD.org> 3 * Copyright (c) 2001-2003 Roman V. Palagin <romanp@unshadow.net> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $SourceForge: flowctl.c,v 1.15 2004/08/31 20:24:58 glebius Exp $ 28 */ 29 30#ifndef lint 31static const char rcs_id[] = 32 "@(#) $FreeBSD: head/usr.sbin/flowctl/flowctl.c 135400 2004-09-17 19:58:03Z glebius $"; 33#endif 34 35#include <sys/types.h> 36#include <sys/time.h> 37#include <sys/socket.h> 38#include <sys/queue.h> 39 40#include <net/if.h> 41#include <netinet/in.h> 42 43#include <arpa/inet.h> 44 45#include <err.h> 46#include <fcntl.h> 47#include <stdio.h> 48#include <stdlib.h> 49#include <string.h> 50#include <unistd.h> 51 52#include <netgraph.h> 53#include <netgraph/netflow/ng_netflow.h> 54 55#define CISCO_SH_FLOW_HEADER "SrcIf SrcIPaddress DstIf DstIPaddress Pr SrcP DstP Pkts\n" 56#define CISCO_SH_FLOW "%-13s %-15s %-13s %-15s %2u %4.4x %4.4x %6lu\n" 57 58int main(int, char **); 59 60static int flow_cache_print(struct ngnf_flows *recs); 61static int ctl_show(int, int, char **); 62static void help(void); 63static void execute_command(int, char **); 64 65struct ip_ctl_cmd { 66 char *cmd_name; 67 int cmd_code; 68 int (*cmd_func)(int code, int argc, char **argv); 69}; 70 71struct ip_ctl_cmd cmds[] = { 72 {"show", NGM_NETFLOW_SHOW, ctl_show}, 73 {NULL, 0, NULL}, 74}; 75 76int cs; 77char ng_nodename[NG_PATHLEN + 1]; 78 79int 80main(int argc, char **argv) 81{ 82 int flags, c; 83 char sname[NG_NODESIZ]; 84 int rcvbuf = SORCVBUF_SIZE; 85 char *ng_name; 86 87 /* parse options */ 88 while ((c = getopt(argc, argv, "d:")) != -1) { 89 switch (c) { 90 case 'd': /* set libnetgraph debug level. */ 91 NgSetDebug(atoi(optarg)); 92 break; 93 } 94 } 95 96 argc -= optind; 97 argv += optind; 98 ng_name = argv[0]; 99 if (ng_name == NULL) 100 help(); 101 argc--; 102 argv++; 103 104 snprintf(ng_nodename, sizeof(ng_nodename), "%s:", ng_name); 105 106 /* create control socket. */ 107 snprintf(sname, sizeof(sname), "flowctl%i", getpid()); 108 109 if (NgMkSockNode(sname, &cs, NULL) == -1) 110 err(1, "NgMkSockNode"); 111 112 /* set control socket nonblocking */ 113 if ((flags = fcntl(cs, F_GETFL, 0)) == -1) 114 err(1, "fcntl(F_GETFL)"); 115 flags |= O_NONBLOCK; 116 if (fcntl(cs, F_SETFL, flags) == -1) 117 err(1, "fcntl(F_SETFL)"); 118 119 /* set receive buffer size */ 120 if (setsockopt(cs, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) == -1) 121 err(1, "setsockopt(SOL_SOCKET, SO_RCVBUF)"); 122 123 /* parse and execute command */ 124 execute_command(argc, argv); 125 126 close(cs); 127 128 exit(0); 129} 130 131static void 132execute_command(int argc, char **argv) 133{ 134 int cindex = -1; 135 int i; 136 137 if (!argc) 138 help(); 139 for (i = 0; cmds[i].cmd_name != NULL; i++) 140 if (!strncmp(argv[0], cmds[i].cmd_name, strlen(argv[0]))) { 141 if (cindex != -1) 142 errx(1, "ambiguous command: %s", argv[0]); 143 cindex = i; 144 } 145 if (cindex == -1) 146 errx(1, "bad command: %s", argv[0]); 147 argc--; 148 argv++; 149 (*cmds[cindex].cmd_func)(cmds[cindex].cmd_code, argc, argv); 150} 151 152static int 153ctl_show(int code, int argc, char **argv) 154{ 155 struct ng_mesg *ng_mesg; 156 struct ngnf_flows *data; 157 char path[NG_PATHLEN + 1]; 158 int token, nread, last = 0; 159 160 ng_mesg = alloca(SORCVBUF_SIZE); 161 162 printf(CISCO_SH_FLOW_HEADER); 163 164 for (;;) { 165 /* request set of accounting records */ 166 token = NgSendMsg(cs, ng_nodename, NGM_NETFLOW_COOKIE, 167 NGM_NETFLOW_SHOW, (void *)&last, sizeof(last)); 168 if (token == -1) 169 err(1, "NgSendMsg(NGM_NETFLOW_SHOW)"); 170 171 /* read reply */ 172 nread = NgRecvMsg(cs, ng_mesg, SORCVBUF_SIZE, path); 173 if (nread == -1) 174 err(1, "NgRecvMsg() failed"); 175 176 if (ng_mesg->header.token != token) 177 err(1, "NgRecvMsg(NGM_NETFLOW_SHOW): token mismatch"); 178 179 data = (struct ngnf_flows*)ng_mesg->data; 180 if ((ng_mesg->header.arglen < (sizeof(*data))) || 181 (ng_mesg->header.arglen < (sizeof(*data) + 182 (data->nentries * sizeof(struct flow_entry_data))))) 183 err(1, "NgRecvMsg(NGM_NETFLOW_SHOW): arglen too small"); 184 185 (void )flow_cache_print(data); 186 187 if (data->last != 0) 188 last = data->last; 189 else 190 break; 191 } 192 193 return (0); 194} 195 196static int 197flow_cache_print(struct ngnf_flows *recs) 198{ 199 struct flow_entry_data *fle; 200 char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN]; 201 char src_if[IFNAMSIZ], dst_if[IFNAMSIZ]; 202 int i; 203 204 /* quick check */ 205 if (recs->nentries == 0) 206 return (0); 207 208 fle = recs->entries; 209 for (i = 0; i < recs->nentries; i++, fle++) { 210 inet_ntop(AF_INET, &fle->r.r_src, src, sizeof(src)); 211 inet_ntop(AF_INET, &fle->r.r_dst, dst, sizeof(dst)); 212 printf(CISCO_SH_FLOW, 213 if_indextoname(fle->fle_i_ifx, src_if), 214 src, 215 if_indextoname(fle->fle_o_ifx, dst_if), 216 dst, 217 fle->r.r_ip_p, 218 ntohs(fle->r.r_sport), 219 ntohs(fle->r.r_dport), 220 fle->packets); 221 222 } 223 224 return (i); 225} 226 227static void 228help(void) 229{ 230 extern char *__progname; 231 232 fprintf(stderr, "usage: %s [-d level] nodename command\n", __progname); 233 exit (0); 234} 235