diff options
author | ume <ume@FreeBSD.org> | 2002-04-11 17:14:22 +0000 |
---|---|---|
committer | ume <ume@FreeBSD.org> | 2002-04-11 17:14:22 +0000 |
commit | 4f51ffc3fede007b2d1c6ce56bdf217f700eb1c7 (patch) | |
tree | 17221edddfe751134988e362f0829a38aa1ab240 /libexec/tftpd | |
parent | f8786d960f554dc901bb184a3bf33ca3ebf0eea2 (diff) | |
download | FreeBSD-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.c | 75 |
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). */ |