sockstat tcp/udp switches

Josh Carroll josh.carroll at psualum.com
Fri Nov 3 23:50:31 UTC 2006


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);
 	}


More information about the freebsd-hackers mailing list