sockstat tcp/udp switches

Josh Carroll josh.carroll at psualum.com
Mon Nov 6 23:17:20 UTC 2006


> I suggest you use /etc/protocols rather than hard code the protocols.
> This will make the code future-proof.  See getprotoent(3) for the
> correct way to read /etc/protocols.

Thanks Peter, that's a great idea. Below is a new patch that uses
getprotoent(3). For now, to maintain backward compatibility, I've
defined a default list of protocols (tcp, udp, divert), in the event
-P is not specified. This should retain the normal command line
behavior.

Thanks again for the suggestion.

Dmitry - with this change, diver is now the default but can also be
specified as an argument to -P as well.

Thanks,
Josh



--- sockstat.c.orig	Thu Jun  9 23:36:03 2005
+++ sockstat.c	Mon Nov  6 15:12:43 2006
@@ -66,8 +66,18 @@
 static int	 opt_u;		/* Show Unix domain sockets */
 static int	 opt_v;		/* Verbose mode */

+/* maximum length of a given protocol name to accept
+  from user input */
+#define MAX_PROTO_LEN 20
+/* default protocols to use if no -P was defined, currently
+	tcp, udp and divert */
+const char *default_protos[] = {"tcp", "udp", "divert", NULL};
+
+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)))
@@ -104,6 +114,104 @@
 	return (len);
 }

+
+/* this function needs to be updated to reflect additional protocols
+	that are to be supported */
+static int
+get_proto_type(const char *proto)
+{
+	struct protoent *pent;
+
+	if(strlen(proto) == 0)
+		return 0;
+
+	pent = malloc(sizeof(struct protoent));
+	pent = getprotobyname(proto);
+	if(pent == NULL) {
+		printf("Unrecognized protocol: %s\n", proto);
+		return -1;
+	} else {
+		return pent->p_proto;
+	}
+}
+
+
+static void init_protos(int num)
+{
+	int proto_count = 0;
+
+	if(num > 0) {
+		proto_count = num;
+	} else {
+		/* find the maximum number of possible protocols */
+		while(getprotoent() != NULL)
+			proto_count++;
+		endprotoent();
+	}
+
+	protos = malloc(sizeof(int) * proto_count);
+}
+
+
+static int
+parse_protos(const char *protospec)
+{
+	const char *p;
+	char curr_proto[MAX_PROTO_LEN];
+	/* to track the current protocol from the protospec */
+	int pindex = 0;
+	int protos_defined = 0;
+	/* the index into the protos integer array to track found
+		protocols */
+	int proto_index = 0;
+	int proto_num;
+
+	/* 0 argument => get all entries  */
+	init_protos(0);
+
+	p = protospec;
+	while(*p != '\0') {
+		if(*p == ',') {
+			curr_proto[pindex] = '\0';
+			if( (proto_num = get_proto_type(curr_proto)) != -1) {
+				protos[proto_index++] = proto_num;
+				protos_defined++;
+			}
+			pindex = 0;
+		} else {
+			curr_proto[pindex++] = *p;
+		}
+		p++;
+		if(*p == '\0' &&  pindex != 0) {
+			curr_proto[pindex] = '\0';
+			if( (proto_num = get_proto_type(curr_proto)) != -1) {
+				protos[proto_index++] = proto_num;
+				protos_defined++;
+			}
+		}
+		if(pindex == MAX_PROTO_LEN) {
+			printf("Warning: truncating protocol\n");
+			curr_proto[pindex] = '\0';
+			if( (proto_num = get_proto_type(curr_proto)) != -1) {
+				protos[proto_index++] = proto_num;
+				protos_defined++;
+			}
+
+			/* 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++;
+
+			pindex = 0;
+		}
+	}
+	return protos_defined;
+}
+
+
 static void
 parse_ports(const char *portspec)
 {
@@ -573,19 +681,49 @@
 	}
 }

+static int set_default_protos(void)
+{
+	struct protoent *prot;
+	const char **curr_proto;
+	int proto_index = 0;
+	int proto_count = 0;
+
+	/* determine the number of default protocols */
+	for(curr_proto = default_protos; *curr_proto; curr_proto++, proto_count++)
+		;
+
+	init_protos(proto_count);
+
+	for(curr_proto = default_protos; *curr_proto; curr_proto++) {
+		prot = getprotobyname(*curr_proto);
+		if(prot == NULL) {
+			printf("Cannot determine default protocols\n");
+			exit(EXIT_FAILURE);
+		}
+		protos[proto_index++] = prot->p_proto;
+	}
+
+	return proto_index;
+}
+
+
 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[])
 {
-	int o;
+	/* if protos_defined remains -1, no -P was provided, sowe avoid
+		attempting to read from that int array later */
+	int protos_defined = -1;

-	while ((o = getopt(argc, argv, "46clp:uv")) != -1)
+	int o, i;
+
+	while ((o = getopt(argc, argv, "46clp:P:uv")) != -1)
 		switch (o) {
 		case '4':
 			opt_4 = 1;
@@ -602,6 +740,9 @@
 		case 'p':
 			parse_ports(optarg);
 			break;
+		case 'P':
+			protos_defined = parse_protos(optarg);
+			break;
 		case 'u':
 			opt_u = 1;
 			break;
@@ -618,17 +759,25 @@
 	if (argc > 0)
 		usage();

-	if (!opt_4 && !opt_6 && !opt_u)
-		opt_4 = opt_6 = opt_u = 1;
+
+	if (!opt_4 && !opt_6 && !opt_u && protos_defined == -1) {
+		opt_u = 1;
+		/* show tcp, udp and divert by default if no -P was specified */
+		/* restore protos_defined to the number of default protocols */
+		protos_defined = set_default_protos();
+	}
+
+	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);
-		gather_inet(IPPROTO_DIVERT);
+		for(i=0; i < protos_defined; i++)
+			gather_inet(protos[i]);
 	}
-	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