summaryrefslogtreecommitdiff
path: root/libexec/tftpd
diff options
context:
space:
mode:
authorHajimu UMEMOTO <ume@FreeBSD.org>2002-04-26 17:22:43 +0000
committerHajimu UMEMOTO <ume@FreeBSD.org>2002-04-26 17:22:43 +0000
commitff14e6e4283d8291d58a7cf1df270f2a6a497ef3 (patch)
tree059599b3b4b03f56d3f6acc23b100ef1ab53a867 /libexec/tftpd
parent33c5350d6a9a9908ef190e9644731c5abb354f52 (diff)
Notes
Diffstat (limited to 'libexec/tftpd')
-rw-r--r--libexec/tftpd/tftpd.c73
1 files changed, 59 insertions, 14 deletions
diff --git a/libexec/tftpd/tftpd.c b/libexec/tftpd/tftpd.c
index b241836544ce..5de0ec9c5d58 100644
--- a/libexec/tftpd/tftpd.c
+++ b/libexec/tftpd/tftpd.c
@@ -87,10 +87,11 @@ int maxtimeout = 5*TIMEOUT;
#define PKTSIZE SEGSIZE+4
char buf[PKTSIZE];
char ackbuf[PKTSIZE];
-struct sockaddr_in from;
+struct sockaddr_storage from;
int fromlen;
void tftp __P((struct tftphdr *, int));
+static void unmappedaddr __P((struct sockaddr_in6 *));
/*
* Null-terminated directory prefix list for absolute pathname requests and
@@ -119,7 +120,8 @@ main(argc, argv)
register struct tftphdr *tp;
register 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(argc, argv)
char *tempchroot;
struct stat sb;
int statret;
+ struct sockaddr_storage ss;
+ char hbuf[NI_MAXHOST];
- tempchroot = inet_ntoa(from.sin_addr);
- asprintf(&tempchroot, "%s/%s", chroot_dir, tempchroot);
+ 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)))
@@ -265,22 +273,37 @@ main(argc, argv)
setuid(nobody->pw_uid);
}
- 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);
}
@@ -352,11 +375,12 @@ again:
}
ecode = (*pf->f_validate)(&filename, tp->th_opcode);
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));
}
@@ -710,3 +734,24 @@ nak(error)
if (send(peer, buf, length, 0) != length)
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);
+}