misc/102162: New Feature (Patch Included): Limit port range for tftpd

Aaron Gifford agifford at infowest.com
Wed Aug 16 21:40:14 UTC 2006


>Number:         102162
>Category:       misc
>Synopsis:       New Feature (Patch Included): Limit port range for tftpd
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Wed Aug 16 21:40:12 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Aaron Gifford
>Release:        6.1-RELEASE
>Organization:
>Environment:
Not applicable
>Description:
NEW FEATURE FOR tftpd:

This patch the TFTP daemon adds a new command line option -p that
permits the user to specify what port or port range the tftpd daemon
will bind to during transfers.  This is useful in cases where one
must limit tftpd (perhaps for firewall reasons) to a small subset
of ports.

The patch applies cleanly to 5.x as well as 6.x up to 6.1-STABLE
as of 16 Aug. 2006.

While this has been tested on IPv4 networks, it has not been tested
on IPv6.  The code is so simple, however, that severe bugs under
IPv6 are unlikely (but it would be nice for someone with an IPv6
net to give it a good walloping test).

-Aaron out.

(The patch is included in the "Fix to the problem" section.)
>How-To-Repeat:

>Fix:
PATCH FOLLOWS:

--- /usr/src/libexec/tftpd/tftpd.c.orig	Tue May 31 11:22:53 2005
+++ /usr/src/libexec/tftpd/tftpd.c	Fri May 12 07:28:28 2006
@@ -130,11 +130,13 @@
 	char *chroot_dir = NULL;
 	struct passwd *nobody;
 	const char *chuser = "nobody";
+	char *pp;
+	u_short startport = 0, endport = 0;
 
 	tzset();			/* syslog in localtime */
 
 	openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
-	while ((ch = getopt(argc, argv, "cClns:u:U:w")) != -1) {
+	while ((ch = getopt(argc, argv, "cClnp:s:u:U:w")) != -1) {
 		switch (ch) {
 		case 'c':
 			ipchroot = 1;
@@ -148,6 +150,17 @@
 		case 'n':
 			suppress_naks = 1;
 			break;
+		case 'p':
+			pp = strchr(optarg, (int)'-');
+			if (pp == NULL) {
+				startport = atoi(optarg);
+				endport = startport;
+			} else {
+				*pp++ = (char)0;
+				startport = atoi(optarg);
+				endport = atoi(pp);
+			}
+			break;
 		case 's':
 			chroot_dir = optarg;
 			break;
@@ -289,19 +302,7 @@
 	}
 
 	len = sizeof(me);
-	if (getsockname(0, (struct sockaddr *)&me, &len) == 0) {
-		switch (me.ss_family) {
-		case AF_INET:
-			((struct sockaddr_in *)&me)->sin_port = 0;
-			break;
-		case AF_INET6:
-			((struct sockaddr_in6 *)&me)->sin6_port = 0;
-			break;
-		default:
-			/* unsupported */
-			break;
-		}
-	} else {
+	if (getsockname(0, (struct sockaddr *)&me, &len) != 0) {
 		memset(&me, 0, sizeof(me));
 		me.ss_family = from.ss_family;
 		me.ss_len = from.ss_len;
@@ -314,9 +315,27 @@
 		syslog(LOG_ERR, "socket: %m");
 		exit(1);
 	}
-	if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
-		syslog(LOG_ERR, "bind: %m");
-		exit(1);
+	while (1) {
+		switch (me.ss_family) {
+		case AF_INET:
+			((struct sockaddr_in *)&me)->sin_port = htons(startport);
+			break;
+		case AF_INET6:
+			((struct sockaddr_in6 *)&me)->sin6_port = htons(startport);
+			break;
+		default:
+			/* unsupported */
+			break;
+		}
+		if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
+			if (errno == EADDRINUSE && startport < endport) {
+				startport++;
+				continue;
+			}
+			syslog(LOG_ERR, "bind: %m");
+			exit(1);
+		}
+		break;
 	}
 	if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
 		syslog(LOG_ERR, "connect: %m");
--- /usr/src/libexec/tftpd/tftpd.8.orig	Wed Jul  7 13:57:14 2004
+++ /usr/src/libexec/tftpd/tftpd.8	Wed May 10 16:36:10 2006
@@ -147,6 +147,21 @@
 .It Fl n
 Suppress negative acknowledgement of requests for nonexistent
 relative filenames.
+.It Fl p Ar port-range
+Force
+.Nm
+to bind to a local udp port within the specified
+.Pa port-range .
+.Nm
+This is useful when the server is behind a firewall because it
+limits the size of hole that must be opened in the firewall for
+to function.  You can specify either a single port number, or
+a port range (two numbers separated by the '-' dash character).
+If you only use a single port, your tftp server will only be
+able to handle a single tftp session at a time.  If you use
+this option, it is recommended that you choose a large enough
+range to support as many concurrent tftp sessions as you
+ever expect to encounter.
 .It Fl s Ar directory
 Cause
 .Nm
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list