[PATCH] netcat with ipv6 and udp

Edgar E. Iglesias edgar.iglesias at axis.com
Wed Dec 28 12:50:31 UTC 2005


Hi all, 

This patch adds support for ipv6 and udp sockets for netcat.

Best regards
-- 
        Programmer
        Edgar E. Iglesias <edgar.iglesias at axis.com> 46.46.272.1946
-------------- next part --------------
Index: networking/nc.c
===================================================================
--- networking/nc.c	(revision 12995)
+++ networking/nc.c	(working copy)
@@ -45,9 +45,98 @@
 	bb_error_msg_and_die("Timed out");
 }
 
+int create_socket(int af, int type, int flags, char *host, char *dport, char *sport) {
+	struct addrinfo hints, *res, *aip;
+	int sockfd = -1;
+	int r;
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_flags    = flags;
+	hints.ai_family   = af;
+	hints.ai_socktype = type;
+		
+	if ((r = getaddrinfo(host, dport, &hints, &res)) != 0)
+		bb_error_msg_and_die(gai_strerror(r));
+	
+	for (aip = res; aip; aip = aip->ai_next) {
+		int on = 1;
+
+		sockfd = socket(aip->ai_family,
+				aip->ai_socktype,
+				aip->ai_protocol);
+
+		if (sockfd < 0)
+			continue;
+		
+		if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) == -1)
+			goto err;
+
+		if (flags & AI_PASSIVE) {
+			int tmpfd;
+#ifdef CONFIG_FEATURE_IPV6
+			if (aip->ai_family == PF_INET6)
+				setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
+					   (char *)&on, sizeof(on));
+#endif
+			if (bind(sockfd, aip->ai_addr, aip->ai_addrlen) != 0)
+				goto err;
+			
+#ifdef CONFIG_NC_UDP
+			if (aip->ai_socktype == SOCK_DGRAM)
+				break;
+#endif
+			
+			if (listen(sockfd, SOMAXCONN) != 0)
+				goto err;
+			
+			if ((tmpfd = accept(sockfd, NULL, NULL)) < 0)
+				goto err;
+				     
+			close(sockfd);
+			sockfd = tmpfd;			
+			break;
+		} else {
+			if (sport) {
+				int lport;
+				struct sockaddr_storage ss;
+				
+				memset(&ss, 0, sizeof ss);
+								
+				lport = bb_lookup_port(sport, "tcp", 0);
+				ss.ss_family = aip->ai_family;
+#ifdef CONFIG_FEATURE_IPV6
+				if (aip->ai_family == AF_INET6) {
+					((struct sockaddr_in6 *)&ss)->sin6_port = lport;
+				}
+				else
+#endif
+				{
+					((struct sockaddr_in *)&ss)->sin_port = lport;
+				}
+				if (bind(sockfd, (struct sockaddr *)&ss, sizeof ss) != 0)
+					goto err;
+			}
+			
+			if (connect(sockfd, aip->ai_addr, aip->ai_addrlen) != 0)
+				goto err;
+			break;
+		}		
+		continue;
+	  err:		
+		close(sockfd);
+		sockfd = -1;
+	}
+	
+	if (sockfd == -1)
+		bb_perror_msg_and_die("socket");
+	
+	freeaddrinfo(res);
+	return sockfd;
+}
+
 int nc_main(int argc, char **argv)
 {
-	int do_listen = 0, lport = 0, delay = 0, wsecs = 0, tmpfd, opt, sfd, x;
+	int do_listen = 0, delay = 0, wsecs = 0, opt, sfd;
 	
 #define buf bb_common_bufsiz1
 	
@@ -55,23 +144,36 @@
 	char *pr00gie = NULL;
 #endif
 
-	struct sockaddr_in address;
-	struct hostent *hostinfo;
-
+	char *sport = NULL;
+	int sock_af = PF_UNSPEC;
+	int sock_type = SOCK_STREAM;
 	fd_set readfds, testfds;
-
-	while ((opt = getopt(argc, argv, "lp:i:e:w:")) > 0) {
+	
+	while ((opt = getopt(argc, argv, "46lp:ui:e:w:")) > 0) {
 		switch (opt) {
-			case 'l':
+#if CONFIG_FEATURE_IPV6
+		        case '4':
+				sock_af = PF_INET;
+				break;
+		        case '6':
+				sock_af = PF_INET6;
+				break;
+#endif
+		        case 'l':
 				do_listen++;
 				break;
 			case 'p':
-				lport = bb_lookup_port(optarg, "tcp", 0);
+				sport = optarg;
 				break;
+#ifdef CONFIG_NC_UDP
+			case 'u':
+				sock_type = SOCK_DGRAM;
+				break;
+#endif				
 			case 'i':
 				delay = atoi(optarg);
 				break;
-#ifdef CONFIG_NC_GAPING_SECURITY_HOLE
+#ifdef GAPING_SECURITY_HOLE
 			case 'e':
 				pr00gie = optarg;
 				break;
@@ -83,56 +185,28 @@
 				bb_show_usage();
 		}
 	}
-
-	if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc))
-		bb_show_usage();
-
-	if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
-		bb_perror_msg_and_die("socket");
-	x = 1;
-	if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1)
-		bb_perror_msg_and_die("reuseaddr");
-	address.sin_family = AF_INET;
-
-	if (wsecs) {
-		signal(SIGALRM, timeout);
-		alarm(wsecs);
+	
+#ifdef GAPING_SECURITY_HOLE
+	if (pr00gie) {
+		/* won't need stdin */
+		close (STDIN_FILENO);      
 	}
-
-	if (lport != 0) {
-		memset(&address.sin_addr, 0, sizeof(address.sin_addr));
-		address.sin_port = lport;
-
-		if (bind(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
-			bb_perror_msg_and_die("bind");
-	}
-
+#endif /* GAPING_SECURITY_HOLE */
+	
+	signal(SIGALRM, timeout);
+	alarm(wsecs);
+	
 	if (do_listen) {
-		socklen_t addrlen = sizeof(address);
-
-		if (listen(sfd, 1) < 0)
-			bb_perror_msg_and_die("listen");
-
-		if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0)
-			bb_perror_msg_and_die("accept");
-
-		close(sfd);
-		sfd = tmpfd;
-	} else {
-		hostinfo = xgethostbyname(argv[optind]);
-
-		address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
-		address.sin_port = bb_lookup_port(argv[optind+1], "tcp", 0);
-
-		if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0)
-			bb_perror_msg_and_die("connect");
+		sfd = create_socket(sock_af == PF_UNSPEC ? PF_INET : sock_af,
+				    sock_type, AI_PASSIVE, NULL, sport, NULL);
 	}
-
-	if (wsecs) {
-		alarm(0);
-		signal(SIGALRM, SIG_DFL);
-	}
-
+	else
+		sfd = create_socket(sock_af, sock_type, 0,
+				    argv[optind], argv[optind + 1], sport);
+	
+	alarm(0);
+	signal(SIGALRM, SIG_DFL);
+	
 #ifdef CONFIG_NC_GAPING_SECURITY_HOLE
 	/* -e given? */
 	if (pr00gie) {
@@ -151,6 +225,11 @@
 	FD_SET(STDIN_FILENO, &readfds);
 
 	while (1) {
+#ifdef CONFIG_NC_UDP
+		struct sockaddr_storage ss;
+		socklen_t slen = sizeof ss;
+		int connected = 0;
+#endif
 		int fd;
 		int ofd;
 		int nread;
@@ -162,10 +241,26 @@
 
 		for (fd = 0; fd < FD_SETSIZE; fd++) {
 			if (FD_ISSET(fd, &testfds)) {
-				if ((nread = safe_read(fd, buf, sizeof(buf))) < 0)
-					bb_perror_msg_and_die(bb_msg_read_error);
-
+#ifdef CONFIG_NC_UDP
 				if (fd == sfd) {
+					if ((nread = recvfrom(fd, buf, sizeof(buf), 0,
+							      (struct sockaddr *)&ss,
+							      &slen)) < 0)
+						bb_perror_msg_and_die("recvfrom");
+					
+					if (sock_type == SOCK_DGRAM && !connected) {
+						if (connect(sfd, (struct sockaddr *)&ss,
+							    sizeof ss))
+							bb_perror_msg_and_die("connect");
+						connected++;
+					}
+				}
+				else
+#endif					
+					if ((nread = safe_read(fd, buf, sizeof(buf))) < 0)
+						bb_perror_msg_and_die("read");
+				
+				if (fd == sfd) {
 					if (nread == 0)
 						exit(0);
 					ofd = STDOUT_FILENO;
Index: networking/Config.in
===================================================================
--- networking/Config.in	(revision 12995)
+++ networking/Config.in	(working copy)
@@ -444,6 +444,13 @@
 	  Add support for executing a program after making or receiving a
 	  successful connection (-e option).
 
+config CONFIG_NC_UDP
+	bool "UDP support"
+	default n
+	depends on CONFIG_NC
+	help
+	  Add support for UDP
+
 config CONFIG_NETSTAT
 	bool "netstat"
 	default n
Index: include/usage.h
===================================================================
--- include/usage.h	(revision 12995)
+++ include/usage.h	(working copy)
@@ -2150,13 +2150,30 @@
 #else
 #  define USAGE_NC_EXEC(a)
 #endif
+#ifdef CONFIG_FEATURE_IPV6
+#  define USAGE_NC_IPV6(a) a
+#else
+#  define USAGE_NC_IPV6(a)
+#endif
+#ifdef CONFIG_NC_UDP
+#  define USAGE_NC_UDP(a) a
+#else
+#  define USAGE_NC_UDP(a)
+#endif
 #define nc_trivial_usage \
 	"[OPTIONS] [IP] [port]"
 #define nc_full_usage \
 	"Netcat opens a pipe to IP:port\n\n" \
 	"Options:\n" \
+	USAGE_NC_IPV6( \
+	"\t-4\t\tUse IPv4\n" \
+	"\t-6\t\tUse IPv6\n" \
+	)\
 	"\t-l\t\tlisten mode, for inbound connects\n" \
 	"\t-p PORT\t\tlocal port number\n" \
+	USAGE_NC_UDP( \
+	"\t-u\t\tUse UDP\n" \
+	) \
 	"\t-i SECS\t\tdelay interval for lines sent\n" \
 	USAGE_NC_EXEC( \
 	"\t-e PROG\t\tprogram to exec after connect (dangerous!)\n" \


More information about the busybox mailing list