From owner-freebsd-hackers@FreeBSD.ORG Fri Nov 3 23:50:31 2006 Return-Path: X-Original-To: freebsd-hackers@freebsd.org Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 06FA216A492 for ; Fri, 3 Nov 2006 23:50:31 +0000 (UTC) (envelope-from josh.carroll@gmail.com) Received: from nf-out-0910.google.com (nf-out-0910.google.com [64.233.182.191]) by mx1.FreeBSD.org (Postfix) with ESMTP id D947643D6E for ; Fri, 3 Nov 2006 23:50:12 +0000 (GMT) (envelope-from josh.carroll@gmail.com) Received: by nf-out-0910.google.com with SMTP id i2so1633037nfe for ; Fri, 03 Nov 2006 15:50:11 -0800 (PST) DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=gmail.com; h=received:message-id:date:from:sender:to:subject:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references:x-google-sender-auth; b=K6bJq95N7LRq1PEw2ZIp2fMm77M9upPB9zS/DUM++8VTkKHoogzMeY98VY2V8QR/EOBjFQNkeIcaWJ92Yun83skgcM6H7VrT+NQ6S/yQb6mujbZvXb2TeAwtfXNi9H+2vIvIi3MxjKcFWAVVSMrtOGdFyxLu942clX4dSctlqbY= Received: by 10.82.135.13 with SMTP id i13mr910860bud.1162597811143; Fri, 03 Nov 2006 15:50:11 -0800 (PST) Received: by 10.82.163.16 with HTTP; Fri, 3 Nov 2006 15:50:10 -0800 (PST) Message-ID: <8cb6106e0611031550y1381b67agdc74144b89de763b@mail.gmail.com> Date: Fri, 3 Nov 2006 15:50:10 -0800 From: "Josh Carroll" Sender: josh.carroll@gmail.com To: freebsd-hackers@freebsd.org In-Reply-To: <20061103025442.GB16543@kobe.laptop> MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline References: <8cb6106e0610311058s7144d38bp2b1dafd114e2b433@mail.gmail.com> <20061102094748.G75543@mignon.ki.iif.hu> <8cb6106e0611021507n6315b629kad8cbbf901343c2@mail.gmail.com> <20061103021803.GC8508@kobe.laptop> <8cb6106e0611021834h17737556y4bb2fda39a4bfa0c@mail.gmail.com> <20061103024621.GB16445@kobe.laptop> <20061103024837.GB79357@lor.one-eyed-alien.net> <20061103025442.GB16543@kobe.laptop> X-Google-Sender-Auth: ad48bb677780bb85 Subject: Re: sockstat tcp/udp switches X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 03 Nov 2006 23:50:31 -0000 Below is an initial attempt at the -P argument implementation. I'm not sure if the method used to parse out the protocol is "up to snuff" for the FreeBSD project, but I'm welcome to suggestions/advice/etc. I tested the previous behavior and given the exact command line, sockstat works the same prior to the patch and with the patch. So the -P option is additive only (so as not to break legacy scripts/automation that may parse the sockstat output). I included a limitation on the maximum length of a proto (mostly to avoid buffer overflows) and 20 is probably way too large, so I can lower that if need be. The -P argument also will sense and ignore multiple commas, e.g.: -P tcp,,udp Will still just detect tcp and udp. I implemented the protocols with a sort of lookup table for the protocol types for arguments to -P. So adding another protocol should be as easy as adding a #define, incrementing the #defined for NUM_PROTOS and updating the add_proto_type function to recognize and properly store the new protocol type. Again, I'm open to any feedback on this particular approach. Thanks again for everyone's attetion on this. It's a nice little project to get me ramped back up into C and I do appreciate all the feedback! Regards, Josh --- sockstat.c.orig Thu Nov 2 15:04:39 2006 +++ sockstat.c Fri Nov 3 15:25:34 2006 @@ -66,8 +66,15 @@ static int opt_u; /* Show Unix domain sockets */ static int opt_v; /* Verbose mode */ +#define NUM_PROTOS 2 +#define MAX_PROTO_LEN 20 +#define TCP_PROTO 0 +#define UDP_PROTO 1 +static int *protos; /* protocols to use */ + static int *ports; + #define INT_BIT (sizeof(int)*CHAR_BIT) #define SET_PORT(p) do { ports[p / INT_BIT] |= 1 << (p % INT_BIT); } while (0) #define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT))) @@ -105,6 +112,97 @@ } static void +clear_protos(void) +{ + int i; + + for(i=0; i <= NUM_PROTOS; i++) + protos[i] = 0; + +} + +static void +init_protos(void) +{ + int i; + + if((protos = calloc(NUM_PROTOS, sizeof(int))) == NULL) + err(1, "calloc()"); + + for(i=0; i <= NUM_PROTOS; i++) + protos[i] = 0; + +} + + +/* this function needs to be updated to reflect additional protocols + that are to be supported */ +static int +add_proto_type(const char *proto) +{ + int found = 0; + + if(strlen(proto) == 0) + return 0; + + if(strncmp(proto, "tcp", 3) == 0) { + protos[TCP_PROTO] = 1; + found = 1; + } + else if(strncmp(proto, "udp", 3) == 0) { + protos[UDP_PROTO] = 1; + found = 1; + } else { + printf("Invalid protocol: %s\n", proto); + } + + return found; +} + +static int +parse_protos(const char *protospec) +{ + const char *p; + char curr_proto[MAX_PROTO_LEN]; + int proto_index = 0; + int protos_defined = 0; + + p = protospec; + while(*p != '\0') { + if(*p == ',') { + curr_proto[proto_index] = '\0'; + protos_defined += add_proto_type(curr_proto); + proto_index = 0; + } else { + curr_proto[proto_index++] = *p; + } + p++; + if(*p == '\0' && proto_index != 0) { + curr_proto[proto_index] = '\0'; + protos_defined += add_proto_type(curr_proto); + } + if(proto_index == MAX_PROTO_LEN) { + printf("Warning: truncating protocol\n"); + curr_proto[proto_index] = '\0'; + protos_defined += add_proto_type(curr_proto); + + /* need to seek to the next , or \0 now */ + while(*p != ',' && *p != '\0') + p++; + + /* if we're at a proto boundary (comma), move on */ + if(*p == ',') + p++; + + proto_index = 0; + } + } + + return protos_defined; +} + + +static void parse_ports(const char *portspec) { const char *p, *q; @@ -576,16 +674,24 @@ static void usage(void) { - fprintf(stderr, "Usage: sockstat [-46clu] [-p ports]\n"); + fprintf(stderr, "Usage: sockstat [-46clu] [-p ports] [-P protos]\n"); exit(1); } int main(int argc, char *argv[]) { + /* if protos_defined remains -1, no -P was provided, sowe avoid + attempting to read from that int array later */ + int protos_defined = -1; + int o; - while ((o = getopt(argc, argv, "46clp:uv")) != -1) + /* initialize all protos to 0, if they're all still unset later + then -P wasn't use and the default is to display all of them */ + init_protos(); + + while ((o = getopt(argc, argv, "46clp:P:uv")) != -1) switch (o) { case '4': opt_4 = 1; @@ -602,6 +708,9 @@ case 'p': parse_ports(optarg); break; + case 'P': + protos_defined = parse_protos(optarg); + break; case 'u': opt_u = 1; break; @@ -618,17 +727,28 @@ if (argc > 0) usage(); - if (!opt_4 && !opt_6 && !opt_u) - opt_4 = opt_6 = opt_u = 1; + /* if -u was explicityl defined, zero out the protos array */ + if(opt_u && protos_defined == -1 && !opt_4 && !opt_6) { + clear_protos(); + protos_defined = 0; + } + + if (!opt_4 && !opt_6 && !opt_u && protos_defined == -1) + opt_u = 1; + if (!opt_4 && !opt_6) + opt_4 = opt_6 = 1; if (!opt_c && !opt_l) opt_c = opt_l = 1; if (opt_4 || opt_6) { - gather_inet(IPPROTO_TCP); - gather_inet(IPPROTO_UDP); + if(protos[TCP_PROTO] == 1 || protos_defined == -1) + gather_inet(IPPROTO_TCP); + if(protos[UDP_PROTO] == 1 || protos_defined == -1) + gather_inet(IPPROTO_UDP); gather_inet(IPPROTO_DIVERT); } - if (opt_u) { + + if ( opt_u || (protos_defined == -1 && !opt_4 && !opt_6)) { gather_unix(SOCK_STREAM); gather_unix(SOCK_DGRAM); }