summaryrefslogtreecommitdiffstats
path: root/libexec/tftpd
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2002-04-11 17:14:22 +0000
committerume <ume@FreeBSD.org>2002-04-11 17:14:22 +0000
commit4f51ffc3fede007b2d1c6ce56bdf217f700eb1c7 (patch)
tree17221edddfe751134988e362f0829a38aa1ab240 /libexec/tftpd
parentf8786d960f554dc901bb184a3bf33ca3ebf0eea2 (diff)
downloadFreeBSD-src-4f51ffc3fede007b2d1c6ce56bdf217f700eb1c7.zip
FreeBSD-src-4f51ffc3fede007b2d1c6ce56bdf217f700eb1c7.tar.gz
IPv6 support for tftp/tftpd.
Obtained from: KAME MFC after: 2 weeks
Diffstat (limited to 'libexec/tftpd')
-rw-r--r--libexec/tftpd/tftpd.c75
1 files changed, 60 insertions, 15 deletions
diff --git a/libexec/tftpd/tftpd.c b/libexec/tftpd/tftpd.c
index 057a3bd..9176f41 100644
--- a/libexec/tftpd/tftpd.c
+++ b/libexec/tftpd/tftpd.c
@@ -88,10 +88,11 @@ int max_rexmtval = 2*TIMEOUT;
#define PKTSIZE SEGSIZE+4
char buf[PKTSIZE];
char ackbuf[PKTSIZE];
-struct sockaddr_in from;
+struct sockaddr_storage from;
int fromlen;
void tftp(struct tftphdr *, int);
+static void unmappedaddr(struct sockaddr_in6 *);
/*
* Null-terminated directory prefix list for absolute pathname requests and
@@ -119,7 +120,8 @@ main(int argc, char *argv[])
struct tftphdr *tp;
int n;
int ch, on;
- struct sockaddr_in sin;
+ struct sockaddr_storage me;
+ int len;
char *chroot_dir = NULL;
struct passwd *nobody;
char *chuser = "nobody";
@@ -244,9 +246,15 @@ main(int argc, char *argv[])
char *tempchroot;
struct stat sb;
int statret;
-
- tempchroot = inet_ntoa(from.sin_addr);
- asprintf(&tempchroot, "%s/%s", chroot_dir, tempchroot);
+ struct sockaddr_storage ss;
+ char hbuf[NI_MAXHOST];
+
+ memcpy(&ss, &from, from.ss_len);
+ unmappedaddr((struct sockaddr_in6 *)&ss);
+ getnameinfo((struct sockaddr *)&ss, ss.ss_len,
+ hbuf, sizeof(hbuf), NULL, 0,
+ NI_NUMERICHOST | NI_WITHSCOPEID);
+ asprintf(&tempchroot, "%s/%s", chroot_dir, hbuf);
statret = stat(tempchroot, &sb);
if ((sb.st_mode & S_IFDIR) &&
(statret == 0 || (statret == -1 && ipchroot == 1)))
@@ -266,22 +274,37 @@ main(int argc, char *argv[])
setgroups(1, &nobody->pw_gid);
}
- from.sin_family = AF_INET;
+ 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 {
+ memset(&me, 0, sizeof(me));
+ me.ss_family = from.ss_family;
+ me.ss_len = from.ss_len;
+ }
alarm(0);
close(0);
close(1);
- peer = socket(AF_INET, SOCK_DGRAM, 0);
+ peer = socket(from.ss_family, SOCK_DGRAM, 0);
if (peer < 0) {
syslog(LOG_ERR, "socket: %m");
exit(1);
}
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+ if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
syslog(LOG_ERR, "bind: %m");
exit(1);
}
- if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
+ if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
syslog(LOG_ERR, "connect: %m");
exit(1);
}
@@ -406,11 +429,12 @@ option_fail:
if (has_options)
oack();
if (logging) {
- char host[MAXHOSTNAMELEN];
+ char hbuf[NI_MAXHOST];
- realhostname(host, sizeof(host) - 1, &from.sin_addr);
- host[sizeof(host) - 1] = '\0';
- syslog(LOG_INFO, "%s: %s request for %s: %s", host,
+ getnameinfo((struct sockaddr *)&from, from.ss_len,
+ hbuf, sizeof(hbuf), NULL, 0,
+ NI_WITHSCOPEID);
+ syslog(LOG_INFO, "%s: %s request for %s: %s", hbuf,
tp->th_opcode == WRQ ? "write" : "read",
filename, errtomsg(ecode));
}
@@ -766,6 +790,27 @@ nak(int error)
syslog(LOG_ERR, "nak: %m");
}
+/* translate IPv4 mapped IPv6 address to IPv4 address */
+static void
+unmappedaddr(struct sockaddr_in6 *sin6)
+{
+ struct sockaddr_in *sin4;
+ u_int32_t addr;
+ int port;
+
+ if (sin6->sin6_family != AF_INET6 ||
+ !IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+ return;
+ sin4 = (struct sockaddr_in *)sin6;
+ addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12];
+ port = sin6->sin6_port;
+ memset(sin4, 0, sizeof(struct sockaddr_in));
+ sin4->sin_addr.s_addr = addr;
+ sin4->sin_port = port;
+ sin4->sin_family = AF_INET;
+ sin4->sin_len = sizeof(struct sockaddr_in);
+}
+
/*
* Send an oack packet (option acknowledgement).
*/
OpenPOWER on IntegriCloud