aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYoshinobu Inoue <shin@FreeBSD.org>2000-01-25 14:52:10 +0000
committerYoshinobu Inoue <shin@FreeBSD.org>2000-01-25 14:52:10 +0000
commit0cac72f42c2f9dfe7953cb3dd7c2e93d1d0c61cf (patch)
treec8a27c2bedbb21bf9014b25f896a4e3240049a25
parent71207448cf3eb42617320efb36e7aa9d76c4c98e (diff)
downloadsrc-0cac72f42c2f9dfe7953cb3dd7c2e93d1d0c61cf.tar.gz
src-0cac72f42c2f9dfe7953cb3dd7c2e93d1d0c61cf.zip
several tcp apps IPv6 update
-inetd -rshd -rlogind -telnetd -rsh -rlogin Reviewed by: freebsd-arch, cvs-committers Obtained from: KAME project
Notes
Notes: svn path=/head/; revision=56590
-rw-r--r--include/unistd.h2
-rw-r--r--lib/libc/net/Makefile.inc4
-rw-r--r--lib/libc/net/rcmd.321
-rw-r--r--lib/libc/net/rcmd.c13
-rw-r--r--lib/libutil/Makefile3
-rw-r--r--lib/libutil/libutil.h3
-rw-r--r--lib/libutil/realhostname.33
-rw-r--r--lib/libutil/realhostname.c95
-rw-r--r--lib/libutil/realhostname_sa.3135
-rw-r--r--libexec/rlogind/Makefile2
-rw-r--r--libexec/rlogind/rlogind.82
-rw-r--r--libexec/rlogind/rlogind.c85
-rw-r--r--libexec/rshd/Makefile3
-rw-r--r--libexec/rshd/rshd.82
-rw-r--r--libexec/rshd/rshd.c83
-rw-r--r--libexec/telnetd/Makefile1
-rw-r--r--libexec/telnetd/telnetd.82
-rw-r--r--libexec/telnetd/telnetd.c88
-rw-r--r--usr.bin/rlogin/rlogin.12
-rw-r--r--usr.bin/rlogin/rlogin.c18
-rw-r--r--usr.bin/rsh/rsh.c6
-rw-r--r--usr.sbin/inetd/Makefile5
-rw-r--r--usr.sbin/inetd/builtins.c88
-rw-r--r--usr.sbin/inetd/inetd.877
-rw-r--r--usr.sbin/inetd/inetd.c616
-rw-r--r--usr.sbin/inetd/inetd.h27
26 files changed, 1186 insertions, 200 deletions
diff --git a/include/unistd.h b/include/unistd.h
index 4fe9e4dccfb8..029546149fdb 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -165,6 +165,8 @@ int profil __P((char *, size_t, vm_offset_t, int));
ssize_t pwrite __P((int, const void *, size_t, off_t));
int rcmd __P((char **, int, const char *,
const char *, const char *, int *));
+int rcmd_af __P((char **, int, const char *,
+ const char *, const char *, int *, int));
char *re_comp __P((const char *));
int re_exec __P((const char *));
int readlink __P((const char *, char *, int));
diff --git a/lib/libc/net/Makefile.inc b/lib/libc/net/Makefile.inc
index 87ac304c2a1f..cde2734fed18 100644
--- a/lib/libc/net/Makefile.inc
+++ b/lib/libc/net/Makefile.inc
@@ -58,7 +58,9 @@ MLINKS+=if_indextoname.3 if_nametoindex.3 if_indextoname.3 if_nameindex.3 \
if_indextoname.3 if_freenameindex.3
MLINKS+=linkaddr.3 link_addr.3 linkaddr.3 link_ntoa.3
#MLINKS+=ns.3 ns_addr.3 ns.3 ns_ntoa.3
-MLINKS+=rcmd.3 iruserok.3 rcmd.3 rresvport.3 rcmd.3 ruserok.3
+MLINKS+=rcmd.3 iruserok.3 rcmd.3 rresvport.3 rcmd.3 ruserok.3 \
+ rcmd.3 iruserok_af.3 rcmd.3 rresvport_af.3 rcmd.3 ruserok_af.3 \
+ rcmd.3 rcmd_af.3
MLINKS+=resolver.3 dn_comp.3 resolver.3 dn_expand.3 resolver.3 res_init.3 \
resolver.3 res_mkquery.3 resolver.3 res_query.3 \
resolver.3 res_search.3 resolver.3 res_send.3
diff --git a/lib/libc/net/rcmd.3 b/lib/libc/net/rcmd.3
index b00f94a3cd72..ed6478bd4600 100644
--- a/lib/libc/net/rcmd.3
+++ b/lib/libc/net/rcmd.3
@@ -40,6 +40,7 @@
.Nm rresvport ,
.Nm iruserok ,
.Nm ruserok ,
+.Nm rcmd_af ,
.Nm rresvport_af ,
.Nm iruserok_af ,
.Nm ruserok_af
@@ -55,7 +56,9 @@
.Ft int
.Fn ruserok "const char *rhost" "int superuser" "const char *ruser" "const char *luser"
.Ft int
-.Fn rresvport_af "int *port" "int family"
+.Fn rcmd_af "char **ahost" "int inport" "const char *locuser" "const char *remuser" "const char *cmd" "int *fd2p" "int af"
+.Ft int
+.Fn rresvport_af "int *port" "int af"
.Ft int
.Fn iruserok_af "void *raddr" "int superuser" "const char *ruser" "const char *luser" "int af"
.Ft int
@@ -184,17 +187,26 @@ It requires trusting the local DNS at most, while the
function requires trusting the entire DNS, which can be spoofed.
.Pp
Functions with ``_af'' suffix, i.e.
+.Fn rcmd_af ,
.Fn rresvport_af ,
-.Fn iruserok_af and
+.Fn iruserok_af
+and
.Fn ruserok_af ,
works just as same as functions without ``_af'', and is capable of
handling both IPv6 port and IPv4 port.
+Functions without
+.Dq Li _af
+works for IPv4 only.
To switch address family,
.Fa af
argument must be filled with
-.Dv AF_INET
+.Dv AF_INET ,
or
.Dv AF_INET6 .
+For
+.Fn rcmd_af ,
+.Dv PF_UNSPEC
+is also allowed.
.Sh DIAGNOSTICS
The
.Fn rcmd
@@ -230,6 +242,9 @@ functions appeared in
.Fn rresvport_af
appeared in RFC2292, and implemented by WIDE project
for Hydrangea IPv6 protocol stack kit.
+.Fn rcmd_af
+appeared in draft-ietf-ipngwg-rfc2292bis-01.txt,
+and implemented by WIDE/KAME IPv6 protocol stack kit.
.Fn iruserok_af
and
.Fn rusreok_af
diff --git a/lib/libc/net/rcmd.c b/lib/libc/net/rcmd.c
index a1416ed79da2..8130410ff45b 100644
--- a/lib/libc/net/rcmd.c
+++ b/lib/libc/net/rcmd.c
@@ -80,6 +80,17 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
const char *locuser, *remuser, *cmd;
int *fd2p;
{
+ return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
+}
+
+int
+rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
+ char **ahost;
+ u_short rport;
+ const char *locuser, *remuser, *cmd;
+ int *fd2p;
+ int af;
+{
struct addrinfo hints, *res, *ai;
struct sockaddr_storage from;
fd_set reads;
@@ -94,7 +105,7 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
- hints.ai_family = AF_UNSPEC;
+ hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
(void)snprintf(num, sizeof(num), "%d", ntohs(rport));
diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile
index f0e9fdac34d1..e79b4add8d05 100644
--- a/lib/libutil/Makefile
+++ b/lib/libutil/Makefile
@@ -5,6 +5,7 @@ LIB= util
SHLIB_MAJOR= 2
SHLIB_MINOR= 2
CFLAGS+=-Wall -DLIBC_SCCS -I${.CURDIR} -I${.CURDIR}/../../sys
+CFLAGS+=-DINET6
SRCS= login.c login_tty.c logout.c logwtmp.c pty.c setproctitle.c \
login_cap.c login_class.c login_auth.c login_times.c login_ok.c \
_secure_path.c uucplock.c property.c auth.c realhostname.c fparseln.c \
@@ -13,7 +14,7 @@ INCS= libutil.h login_cap.h
MAN3+= login.3 login_auth.3 login_tty.3 logout.3 logwtmp.3 pty.3 \
setproctitle.3 login_cap.3 login_class.3 login_times.3 login_ok.3 \
_secure_path.3 uucplock.3 property.3 auth.3 realhostname.3 \
- trimdomain.3 fparseln.3
+ realhostname_sa.3 trimdomain.3 fparseln.3
MAN5+= login.conf.5 auth.conf.5
MLINKS+= property.3 properties_read.3 property.3 properties_free.3
MLINKS+= property.3 property_find.3
diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h
index 492370043f7a..927a384fa435 100644
--- a/lib/libutil/libutil.h
+++ b/lib/libutil/libutil.h
@@ -60,6 +60,9 @@ void properties_free __P((properties list));
char *property_find __P((properties list, const char *name));
char *auth_getval __P((const char *name));
int realhostname __P((char *host, size_t hsize, const struct in_addr *ip));
+struct sockaddr;
+int realhostname_sa __P((char *host, size_t hsize, struct sockaddr *addr,
+ int addrlen));
#ifdef _STDIO_H_ /* avoid adding new includes */
char *fparseln __P((FILE *, size_t *, size_t *, const char[3], int));
#endif
diff --git a/lib/libutil/realhostname.3 b/lib/libutil/realhostname.3
index 1f2e6a9b8f6b..acf370b9d168 100644
--- a/lib/libutil/realhostname.3
+++ b/lib/libutil/realhostname.3
@@ -103,4 +103,5 @@ now contains the numeric value of
.Sh SEE ALSO
.Xr gethostbyaddr 3 ,
.Xr gethostbyname 3 ,
-.Xr inet_ntoa 3
+.Xr inet_ntoa 3 ,
+.Xr realhostname_sa 3
diff --git a/lib/libutil/realhostname.c b/lib/libutil/realhostname.c
index fa7f4b1a9805..7236890dab0b 100644
--- a/lib/libutil/realhostname.c
+++ b/lib/libutil/realhostname.c
@@ -38,6 +38,17 @@
#include "libutil.h"
+/* wrapper for KAME-special getnameinfo() */
+#ifndef NI_WITHSCOPEID
+#define NI_WITHSCOPEID 0
+#endif
+
+struct sockinet {
+ u_char si_len;
+ u_char si_family;
+ u_short si_port;
+};
+
int
realhostname(char *host, size_t hsize, const struct in_addr *ip)
{
@@ -71,3 +82,87 @@ realhostname(char *host, size_t hsize, const struct in_addr *ip)
return result;
}
+
+int
+realhostname_sa(char *host, size_t hsize, struct sockaddr *addr, int addrlen)
+{
+ int result, error;
+
+ result = HOSTNAME_INVALIDADDR;
+
+ error = getnameinfo(addr, addrlen, host, hsize, NULL, 0, 0);
+ if (error == NULL) {
+ struct addrinfo hints, *res, *ores;
+ struct sockaddr *sa;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_CANONNAME;
+
+ error = getaddrinfo(host, NULL, &hints, &res);
+ if (error) {
+ result = HOSTNAME_INVALIDNAME;
+ goto numeric;
+ } else for (ores = res; ; res = res->ai_next) {
+ if (res == NULL) {
+ freeaddrinfo(ores);
+ result = HOSTNAME_INCORRECTNAME;
+ goto numeric;
+ }
+ sa = res->ai_addr;
+ if (sa == NULL) {
+ freeaddrinfo(ores);
+ result = HOSTNAME_INCORRECTNAME;
+ goto numeric;
+ }
+ if (sa->sa_len == addrlen &&
+ sa->sa_family == addr->sa_family) {
+ u_int16_t port;
+
+ port = ((struct sockinet *)addr)->si_port;
+ ((struct sockinet *)addr)->si_port = 0;
+ if (!memcmp(sa, addr, sa->sa_len)) {
+ strncpy(host, res->ai_canonname,
+ hsize);
+ result = HOSTNAME_FOUND;
+ ((struct sockinet *)addr)->si_port =
+ port;
+ break;
+ }
+ ((struct sockinet *)addr)->si_port = port;
+ }
+#ifdef INET6
+ /*
+ * XXX IPv4 mapped IPv6 addr consideraton,
+ * specified in rfc2373.
+ */
+ if (sa->sa_family == AF_INET &&
+ addr->sa_family == AF_INET6) {
+ struct in_addr *in;
+ struct in6_addr *in6;
+
+ in = &((struct sockaddr_in *)sa)->sin_addr;
+ in6 = &((struct sockaddr_in6 *)addr)->sin6_addr;
+ if (IN6_IS_ADDR_V4MAPPED(in6) &&
+ !memcmp(&in6->s6_addr[12], in,
+ sizeof(*in))) {
+ strncpy(host, res->ai_canonname,
+ hsize);
+ result = HOSTNAME_FOUND;
+ break;
+ }
+ }
+#endif
+ }
+ freeaddrinfo(ores);
+ } else {
+ numeric:
+ getnameinfo(addr, addrlen, host, hsize, NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
+ /* XXX: do 'error' check */
+ }
+
+ return result;
+}
+
+
diff --git a/lib/libutil/realhostname_sa.3 b/lib/libutil/realhostname_sa.3
new file mode 100644
index 000000000000..6fef960a24d8
--- /dev/null
+++ b/lib/libutil/realhostname_sa.3
@@ -0,0 +1,135 @@
+.\" Copyright (C) 1995, 1996, 1997, 1998, 1999, and 2000 WIDE Project.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the project nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd January 11, 2000
+.Os
+.Dt REALHOSTNAME_SA 3
+.Sh NAME
+.Nm realhostname_sa
+.Nd "convert an struct sockaddr to the real host name"
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <netinet/in.h>
+.Fd #include <libutil.h>
+.Ft int
+.Fn realhostname_sa "char *host" "size_t hsize" "struct sockaddr *addr" \
+"int addrlen"
+.Pp
+Link with
+.Va -lutil
+on the
+.Xr cc 1
+command line.
+.Sh DESCRIPTION
+The function
+.Fn realhostname_sa
+converts
+.Ar addr
+to the corresponding host name. This is done by resolving
+.Ar addr
+to a host name and then ensuring that the host name resolves
+back to
+.Ar addr .
+.Pp
+.Ar host
+must point to a buffer of at least
+.Ar hsize
+bytes, and will always be written to by this function.
+.Pp
+If the name resolution doesn't work both ways or if the host name is longer
+than
+.Ar hsize
+bytes,
+.Xr getnameinfo 3
+with NI_NUMERICHOST specified, is used to convert
+.Ar addr
+to an ASCII form.
+.Pp
+If the string written to
+.Ar host
+is
+.Ar hsize
+bytes long,
+.Ar host
+will not be NUL terminated.
+.Sh RETURN VALUES
+.Fn realhostname_sa
+will return one of the following constants which are defined in
+.Pa libutil.h :
+.Pp
+.Bl -tag -width XXX -offset XXX
+.It Li HOSTNAME_FOUND
+A valid host name was found.
+.It Li HOSTNAME_INCORRECTNAME
+A host name was found, but it did not resolve back to the passed
+.Ar ip .
+.Ar host
+now contains the numeric value of
+.Ar ip .
+.It Li HOSTNAME_INVALIDADDR
+.Ar ip
+could not be resolved.
+.Ar host
+now contains the numeric value of
+.Ar ip .
+.It Li HOSTNAME_INVALIDNAME
+A host name was found, but it could not be resolved back to any ip number.
+.Ar host
+now contains the numeric value of
+.Ar ip .
+.El
+.Sh SEE ALSO
+.Xr getaddrinfo 3 ,
+.Xr getnameinfo 3 ,
+.Xr realhostname 3
+
diff --git a/libexec/rlogind/Makefile b/libexec/rlogind/Makefile
index bae4a4b542ed..f22df18a1bf8 100644
--- a/libexec/rlogind/Makefile
+++ b/libexec/rlogind/Makefile
@@ -6,7 +6,7 @@ SRCS= rlogind.c
MAN8= rlogind.8
DPADD= ${LIBUTIL}
LDADD= -lutil
-CFLAGS+= -Wall
+CFLAGS+= -Wall -DINET6
.if defined(NOPAM)
CFLAGS+= -DNO_PAM
diff --git a/libexec/rlogind/rlogind.8 b/libexec/rlogind/rlogind.8
index 14d7a93de5f0..969fb084496e 100644
--- a/libexec/rlogind/rlogind.8
+++ b/libexec/rlogind/rlogind.8
@@ -204,3 +204,5 @@ The
.Nm
command appeared in
.Bx 4.2 .
+.Pp
+IPv6 support was added by WIDE/KAME project. \ No newline at end of file
diff --git a/libexec/rlogind/rlogind.c b/libexec/rlogind/rlogind.c
index 111a56bff5f7..817f6c857ae5 100644
--- a/libexec/rlogind/rlogind.c
+++ b/libexec/rlogind/rlogind.c
@@ -91,6 +91,11 @@ static const char rcsid[] =
#define ARGSTR "Dalnx"
+/* wrapper for KAME-special getnameinfo() */
+#ifndef NI_WITHSCOPEID
+#define NI_WITHSCOPEID 0
+#endif
+
char *env[2];
#define NMAX 30
char lusername[NMAX+1], rusername[NMAX+1];
@@ -102,12 +107,25 @@ int no_delay;
struct passwd *pwd;
-void doit __P((int, struct sockaddr_in *));
+union sockunion {
+ struct sockinet {
+ u_char si_len;
+ u_char si_family;
+ u_short si_port;
+ } su_si;
+ struct sockaddr_in su_sin;
+ struct sockaddr_in6 su_sin6;
+};
+#define su_len su_si.si_len
+#define su_family su_si.si_family
+#define su_port su_si.si_port
+
+void doit __P((int, union sockunion *));
int control __P((int, char *, int));
void protocol __P((int, int));
void cleanup __P((int));
void fatal __P((int, char *, int));
-int do_rlogin __P((struct sockaddr_in *));
+int do_rlogin __P((union sockunion *));
void getstr __P((char *, int, char *));
void setup_term __P((int));
int do_krb_login __P((struct sockaddr_in *));
@@ -123,7 +141,7 @@ main(argc, argv)
char *argv[];
{
extern int __check_rhosts_file;
- struct sockaddr_in from;
+ union sockunion from;
int ch, fromlen, on;
openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH);
@@ -168,9 +186,12 @@ main(argc, argv)
if (no_delay &&
setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
+ if (from.su_family == AF_INET)
+ {
on = IPTOS_LOWDELAY;
if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+ }
doit(0, &from);
return 0;
@@ -187,11 +208,12 @@ struct winsize win = { 0, 0, 0, 0 };
void
doit(f, fromp)
int f;
- struct sockaddr_in *fromp;
+ union sockunion *fromp;
{
int master, pid, on = 1;
int authenticated = 0;
- char hostname[MAXHOSTNAMELEN];
+ char hostname[2 * MAXHOSTNAMELEN + 1];
+ char nameinfo[2 * INET6_ADDRSTRLEN + 1];
char c;
alarm(60);
@@ -201,20 +223,33 @@ doit(f, fromp)
exit(1);
alarm(0);
- fromp->sin_port = ntohs((u_short)fromp->sin_port);
- realhostname(hostname, sizeof(hostname) - 1, &fromp->sin_addr);
+
+ realhostname_sa(hostname, sizeof(hostname) - 1,
+ (struct sockaddr *)fromp, fromp->su_len);
+ /* error check ? */
+ fromp->su_port = ntohs((u_short)fromp->su_port);
hostname[sizeof(hostname) - 1] = '\0';
{
- if (fromp->sin_family != AF_INET ||
- fromp->sin_port >= IPPORT_RESERVED ||
- fromp->sin_port < IPPORT_RESERVED/2) {
+ if ((fromp->su_family != AF_INET &&
+#ifdef INET6
+ fromp->su_family != AF_INET6
+#endif
+ ) ||
+ fromp->su_port >= IPPORT_RESERVED ||
+ fromp->su_port < IPPORT_RESERVED/2) {
+ getnameinfo((struct sockaddr *)fromp,
+ fromp->su_len,
+ nameinfo, sizeof(nameinfo), NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
+ /* error check ? */
syslog(LOG_NOTICE, "Connection from %s on illegal port",
- inet_ntoa(fromp->sin_addr));
+ nameinfo);
fatal(f, "Permission denied", 0);
}
#ifdef IP_OPTIONS
- {
+ if (fromp->su_family == AF_INET)
+ {
u_char optbuf[BUFSIZ/3];
int optsize = sizeof(optbuf), ipproto, i;
struct protoent *ip;
@@ -230,7 +265,7 @@ doit(f, fromp)
if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
syslog(LOG_NOTICE,
"Connection refused from %s with IP option %s",
- inet_ntoa(fromp->sin_addr),
+ inet_ntoa(fromp->su_sin.sin_addr),
c == IPOPT_LSRR ? "LSRR" : "SSRR");
exit(1);
}
@@ -239,7 +274,7 @@ doit(f, fromp)
i += (c == IPOPT_NOP) ? 1 : optbuf[i+1];
}
}
- }
+ }
#endif
if (do_rlogin(fromp) == 0)
authenticated++;
@@ -533,9 +568,11 @@ fatal(f, msg, syserr)
int
do_rlogin(dest)
- struct sockaddr_in *dest;
+ union sockunion *dest;
{
int retval;
+ int af;
+ char *addr;
getstr(rusername, sizeof(rusername), "remuser too long");
getstr(lusername, sizeof(lusername), "locuser too long");
@@ -559,8 +596,22 @@ do_rlogin(dest)
if (pwd == NULL)
return (-1);
/* XXX why don't we syslog() failure? */
- return (iruserok(dest->sin_addr.s_addr, pwd->pw_uid == 0,
- rusername, lusername));
+
+ af = dest->su_family;
+ switch (af) {
+ case AF_INET:
+ addr = (char *)&dest->su_sin.sin_addr;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ addr = (char *)&dest->su_sin6.sin6_addr;
+ break;
+#endif
+ default:
+ return -1; /*EAFNOSUPPORT*/
+ }
+
+ return (iruserok_af(addr, pwd->pw_uid == 0, rusername, lusername, af));
}
void
diff --git a/libexec/rshd/Makefile b/libexec/rshd/Makefile
index 20051220d5d4..ca0d15571944 100644
--- a/libexec/rshd/Makefile
+++ b/libexec/rshd/Makefile
@@ -19,6 +19,9 @@ CFLAGS+=-DLOGIN_CAP -Wall
DPADD+= ${LIBUTIL}
LDADD+= -lutil
+# IPv6 support
+CFLAGS+= -DINET6
+
.include <bsd.prog.mk>
.PATH: ${.CURDIR}/../rlogind
diff --git a/libexec/rshd/rshd.8 b/libexec/rshd/rshd.8
index 80cdbc121b7e..cba4482762eb 100644
--- a/libexec/rshd/rshd.8
+++ b/libexec/rshd/rshd.8
@@ -250,3 +250,5 @@ A facility to allow all data exchanges to be encrypted should be
present.
.Pp
A more extensible protocol (such as Telnet) should be used.
+.Sh HISTORY
+IPv6 support was added by WIDE/KAME project.
diff --git a/libexec/rshd/rshd.c b/libexec/rshd/rshd.c
index 8533644663f7..54fa4a69d0fa 100644
--- a/libexec/rshd/rshd.c
+++ b/libexec/rshd/rshd.c
@@ -80,6 +80,11 @@ static const char rcsid[] =
#include <login_cap.h>
#endif
+/* wrapper for KAME-special getnameinfo() */
+#ifndef NI_WITHSCOPEID
+#define NI_WITHSCOPEID 0
+#endif
+
int keepalive = 1;
int log_success; /* If TRUE, log all successful accesses */
int sent_null;
@@ -88,7 +93,20 @@ int no_delay;
int doencrypt = 0;
#endif
-void doit __P((struct sockaddr_in *));
+union sockunion {
+ struct sockinet {
+ u_char si_len;
+ u_char si_family;
+ u_short si_port;
+ } su_si;
+ struct sockaddr_in su_sin;
+ struct sockaddr_in6 su_sin6;
+};
+#define su_len su_si.si_len
+#define su_family su_si.si_family
+#define su_port su_si.si_port
+
+void doit __P((union sockunion *));
void error __P((const char *, ...));
void getstr __P((char *, int, char *));
int local_domain __P((char *));
@@ -109,7 +127,7 @@ main(argc, argv)
extern int __check_rhosts_file;
struct linger linger;
int ch, on = 1, fromlen;
- struct sockaddr_in from;
+ struct sockaddr_storage from;
openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
@@ -169,7 +187,7 @@ main(argc, argv)
if (no_delay &&
setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
- doit(&from);
+ doit((union sockunion *)&from);
/* NOTREACHED */
return(0);
}
@@ -184,7 +202,7 @@ char **environ;
void
doit(fromp)
- struct sockaddr_in *fromp;
+ union sockunion *fromp;
{
extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c. */
struct passwd *pwd;
@@ -195,7 +213,9 @@ doit(fromp)
char *errorstr;
char *cp, sig, buf[BUFSIZ];
char cmdbuf[NCARGS+1], locuser[16], remuser[16];
- char fromhost[MAXHOSTNAMELEN];
+ char fromhost[2 * MAXHOSTNAMELEN + 1];
+ char numericname[INET6_ADDRSTRLEN];
+ int af = fromp->su_family, err;
int retval;
#ifdef CRYPT
int rc;
@@ -216,14 +236,21 @@ doit(fromp)
}
}
#endif
- fromp->sin_port = ntohs((u_short)fromp->sin_port);
- if (fromp->sin_family != AF_INET) {
- syslog(LOG_ERR, "malformed \"from\" address (af %d)",
- fromp->sin_family);
+ fromp->su_port = ntohs((u_short)fromp->su_port);
+ if (af != AF_INET
+#ifdef INET6
+ && af != AF_INET6
+#endif
+ ) {
+ syslog(LOG_ERR, "malformed \"from\" address (af %d)\n", af);
exit(1);
}
+ err = getnameinfo((struct sockaddr *)fromp, fromp->su_len, numericname,
+ sizeof(numericname), NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
+ /* XXX: do 'err' check */
#ifdef IP_OPTIONS
- {
+ if (af == AF_INET) {
u_char optbuf[BUFSIZ/3];
int optsize = sizeof(optbuf), ipproto, i;
struct protoent *ip;
@@ -239,7 +266,7 @@ doit(fromp)
if (c == IPOPT_LSRR || c == IPOPT_SSRR) {
syslog(LOG_NOTICE,
"connection refused from %s with IP option %s",
- inet_ntoa(fromp->sin_addr),
+ numericname,
c == IPOPT_LSRR ? "LSRR" : "SSRR");
exit(1);
}
@@ -251,12 +278,12 @@ doit(fromp)
}
#endif
- if (fromp->sin_port >= IPPORT_RESERVED ||
- fromp->sin_port < IPPORT_RESERVED/2) {
+ if (fromp->su_port >= IPPORT_RESERVED ||
+ fromp->su_port < IPPORT_RESERVED/2) {
syslog(LOG_NOTICE|LOG_AUTH,
"connection from %s on illegal port %u",
- inet_ntoa(fromp->sin_addr),
- fromp->sin_port);
+ numericname,
+ fromp->su_port);
exit(1);
}
@@ -279,7 +306,7 @@ doit(fromp)
(void) alarm(0);
if (port != 0) {
int lport = IPPORT_RESERVED - 1;
- s = rresvport(&lport);
+ s = rresvport_af(&lport, af);
if (s < 0) {
syslog(LOG_ERR, "can't get stderr port: %m");
exit(1);
@@ -288,11 +315,11 @@ doit(fromp)
port < IPPORT_RESERVED/2) {
syslog(LOG_NOTICE|LOG_AUTH,
"2nd socket from %s on unreserved port %u",
- inet_ntoa(fromp->sin_addr),
+ numericname,
port);
exit(1);
}
- fromp->sin_port = htons(port);
+ fromp->su_port = htons(port);
if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) {
syslog(LOG_INFO, "connect second port %d: %m", port);
exit(1);
@@ -300,11 +327,13 @@ doit(fromp)
}
errorstr = NULL;
- realhostname(fromhost, sizeof(fromhost) - 1, &fromp->sin_addr);
+ realhostname_sa(fromhost, sizeof(fromhost) - 1,
+ (struct sockaddr *)fromp,
+ fromp->su_len);
fromhost[sizeof(fromhost) - 1] = '\0';
#ifdef CRYPT
- if (doencrypt) {
+ if (doencrypt && af == AF_INET) {
struct sockaddr_in local_addr;
rc = sizeof(local_addr);
if (getsockname(0, (struct sockaddr *)&local_addr,
@@ -379,8 +408,14 @@ doit(fromp)
if (errorstr ||
(pwd->pw_expire && time(NULL) >= pwd->pw_expire) ||
(pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
- iruserok(fromp->sin_addr.s_addr, pwd->pw_uid == 0,
- remuser, locuser) < 0)) {
+ iruserok_af(
+#ifdef INET6
+ (af == AF_INET6)
+ ? (void *)&fromp->su_sin6.sin6_addr :
+#endif
+ (void *)&fromp->su_sin.sin_addr,
+ pwd->pw_uid == 0,
+ remuser, locuser, af) < 0)) {
if (__rcmd_errstr)
syslog(LOG_INFO|LOG_AUTH,
"%s@%s as %s: permission denied (%s). cmd='%.80s'",
@@ -402,10 +437,10 @@ fail:
exit(1);
}
#ifdef LOGIN_CAP
- if (lc != NULL) {
+ if (lc != NULL && fromp->su_family == AF_INET) { /*XXX*/
char remote_ip[MAXHOSTNAMELEN];
- strncpy(remote_ip, inet_ntoa(fromp->sin_addr),
+ strncpy(remote_ip, numericname,
sizeof(remote_ip) - 1);
remote_ip[sizeof(remote_ip) - 1] = 0;
if (!auth_hostok(lc, fromhost, remote_ip)) {
diff --git a/libexec/telnetd/Makefile b/libexec/telnetd/Makefile
index 068087a62c65..7766276ca15f 100644
--- a/libexec/telnetd/Makefile
+++ b/libexec/telnetd/Makefile
@@ -6,6 +6,7 @@ CFLAGS+=-DLINEMODE -DUSE_TERMIO -DDIAGNOSTICS
#CFLAGS+=-DKLUDGELINEMODE
CFLAGS+=-DOLD_ENVIRON -DENV_HACK
CFLAGS+=-I${.CURDIR}/../../lib
+CFLAGS+=-DINET6
SRCS= global.c slc.c state.c sys_term.c telnetd.c \
termstat.c utility.c
DPADD= ${LIBUTIL} ${LIBTERMCAP} ${LIBTELNET}
diff --git a/libexec/telnetd/telnetd.8 b/libexec/telnetd/telnetd.8
index a2973ef611f3..06e98f946deb 100644
--- a/libexec/telnetd/telnetd.8
+++ b/libexec/telnetd/telnetd.8
@@ -623,3 +623,5 @@ never sends
.Tn TELNET
.Dv IAC GA
(go ahead) commands.
+.Sh HISTORY
+IPv6 support was added by WIDE/KAME project. \ No newline at end of file
diff --git a/libexec/telnetd/telnetd.c b/libexec/telnetd/telnetd.c
index 5141c2aecf42..57a972aaf10e 100644
--- a/libexec/telnetd/telnetd.c
+++ b/libexec/telnetd/telnetd.c
@@ -71,6 +71,12 @@ static const char rcsid[] =
#include <sys/secparm.h>
#include <sys/usrv.h>
# endif /* SO_SEC_MULTI */
+
+/* wrapper for KAME-special getnameinfo() */
+#ifndef NI_WITHSCOPEID
+#define NI_WITHSCOPEID 0
+#endif
+
int secflag;
char tty_dev[16];
struct secdev dv;
@@ -137,7 +143,7 @@ int debug = 0;
int keepalive = 1;
char *altlogin;
-void doit __P((struct sockaddr_in *));
+void doit __P((struct sockaddr *));
int terminaltypeok __P((char *));
void startslave __P((char *, int, char *));
extern void usage P((void));
@@ -149,6 +155,7 @@ extern void usage P((void));
*/
char valid_opts[] = {
'd', ':', 'h', 'k', 'n', 'p', ':', 'S', ':', 'u', ':', 'U',
+ '4', '6',
#ifdef AUTHENTICATION
'a', ':', 'X', ':',
#endif
@@ -173,11 +180,13 @@ char valid_opts[] = {
'\0'
};
- int
+int family = AF_INET;
+
+int
main(argc, argv)
char *argv[];
{
- struct sockaddr_in from;
+ struct sockaddr_storage from;
int on = 1, fromlen;
register int ch;
#if defined(IPPROTO_IP) && defined(IP_TOS)
@@ -381,6 +390,16 @@ main(argc, argv)
break;
#endif /* AUTHENTICATION */
+ case '4':
+ family = AF_INET;
+ break;
+
+#ifdef INET6
+ case '6':
+ family = AF_INET6;
+ break;
+#endif
+
default:
warnx("%c: unknown option", ch);
/* FALLTHROUGH */
@@ -394,43 +413,41 @@ main(argc, argv)
argv += optind;
if (debug) {
- int s, ns, foo;
- struct servent *sp;
- static struct sockaddr_in sin = { AF_INET };
+ int s, ns, foo, error;
+ char *service = "telnet";
+ struct addrinfo hints, *res;
if (argc > 1) {
usage();
/* NOT REACHED */
- } else if (argc == 1) {
- if ((sp = getservbyname(*argv, "tcp"))) {
- sin.sin_port = sp->s_port;
- } else {
- sin.sin_port = atoi(*argv);
- if ((int)sin.sin_port <= 0) {
- warnx("%s: bad port #", *argv);
- usage();
- /* NOT REACHED */
- }
- sin.sin_port = htons((u_short)sin.sin_port);
- }
- } else {
- sp = getservbyname("telnet", "tcp");
- if (sp == 0)
- errx(1, "tcp/telnet: unknown service");
- sin.sin_port = sp->s_port;
+ } else if (argc == 1)
+ service = *argv;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ error = getaddrinfo(NULL, service, &hints, &res);
+
+ if (error) {
+ errx(1, "tcp/%s: %s\n", service, gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ errx(1, "tcp/%s: %s\n", service, strerror(errno));
+ usage();
}
- s = socket(AF_INET, SOCK_STREAM, 0);
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (s < 0)
err(1, "socket");
(void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
- if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0)
+ if (bind(s, res->ai_addr, res->ai_addrlen) < 0)
err(1, "bind");
if (listen(s, 1) < 0)
err(1, "listen");
- foo = sizeof sin;
- ns = accept(s, (struct sockaddr *)&sin, &foo);
+ foo = res->ai_addrlen;
+ ns = accept(s, res->ai_addr, &foo);
if (ns < 0)
err(1, "accept");
(void) dup2(ns, 0);
@@ -512,7 +529,7 @@ main(argc, argv)
}
#if defined(IPPROTO_IP) && defined(IP_TOS)
- {
+ if (from.ss_family == AF_INET) {
# if defined(HAS_GETTOS)
struct tosent *tp;
if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
@@ -528,7 +545,7 @@ main(argc, argv)
}
#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
net = 0;
- doit(&from);
+ doit((struct sockaddr *)&from);
/* NOTREACHED */
return(0);
} /* end of main */
@@ -773,8 +790,9 @@ char user_name[256];
*/
void
doit(who)
- struct sockaddr_in *who;
+ struct sockaddr *who;
{
+ int err;
int ptynum;
/*
@@ -817,16 +835,18 @@ doit(who)
#endif /* _SC_CRAY_SECURE_SYS */
/* get name of connected client */
- if (realhostname(remote_hostname, sizeof(remote_hostname) - 1,
- &who->sin_addr) == HOSTNAME_INVALIDADDR && registerd_host_only)
+ if (realhostname_sa(remote_hostname, sizeof(remote_hostname) - 1,
+ who, who->sa_len) == HOSTNAME_INVALIDADDR && registerd_host_only)
fatal(net, "Couldn't resolve your address into a host name.\r\n\
Please contact your net administrator");
remote_hostname[sizeof(remote_hostname) - 1] = '\0';
trimdomain(remote_hostname, UT_HOSTSIZE);
if (!isdigit(remote_hostname[0]) && strlen(remote_hostname) > utmp_len)
- strncpy(remote_hostname, inet_ntoa(who->sin_addr),
- sizeof(remote_hostname) - 1);
+ err = getnameinfo(who, who->sa_len, remote_hostname,
+ sizeof(remote_hostname), NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
+ /* XXX: do 'err' check */
(void) gethostname(host_name, sizeof(host_name) - 1);
host_name[sizeof(host_name) - 1] = '\0';
diff --git a/usr.bin/rlogin/rlogin.1 b/usr.bin/rlogin/rlogin.1
index e2fa76ce0847..3e3a749bf78e 100644
--- a/usr.bin/rlogin/rlogin.1
+++ b/usr.bin/rlogin/rlogin.1
@@ -226,6 +226,8 @@ The
.Nm
command appeared in
.Bx 4.2 .
+.Pp
+IPv6 support was added by WIDE/KAME project.
.Sh BUGS
.Nm Rlogin
will be replaced by
diff --git a/usr.bin/rlogin/rlogin.c b/usr.bin/rlogin/rlogin.c
index 0df97a34bcf0..4f2cb6bfb112 100644
--- a/usr.bin/rlogin/rlogin.c
+++ b/usr.bin/rlogin/rlogin.c
@@ -154,6 +154,8 @@ main(argc, argv)
#ifdef KERBEROS
char *k;
#endif
+ struct sockaddr_storage ss;
+ int sslen;
argoff = dflag = Dflag = 0;
one = 1;
@@ -331,10 +333,11 @@ main(argc, argv)
if (doencrypt)
errx(1, "the -x flag requires Kerberos authentication");
#endif /* CRYPT */
- rem = rcmd(&host, sp->s_port, localname, user, term, 0);
+ rem = rcmd_af(&host, sp->s_port, localname, user, term, 0,
+ PF_UNSPEC);
}
#else
- rem = rcmd(&host, sp->s_port, localname, user, term, 0);
+ rem = rcmd_af(&host, sp->s_port, localname, user, term, 0, PF_UNSPEC);
#endif /* KERBEROS */
if (rem < 0)
@@ -347,9 +350,16 @@ main(argc, argv)
setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0)
warn("setsockopt NODELAY (ignored)");
+ sslen = sizeof(ss);
one = IPTOS_LOWDELAY;
- if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
- warn("setsockopt TOS (ignored)");
+ if (getsockname(rem, (struct sockaddr *)&ss, &sslen) == 0 &&
+ ss.ss_family == AF_INET) {
+ if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one,
+ sizeof(int)) < 0)
+ warn("setsockopt TOS (ignored)");
+ } else
+ if (ss.ss_family == AF_INET)
+ warn("setsockopt getsockname failed");
(void)setuid(uid);
doit(omask);
diff --git a/usr.bin/rsh/rsh.c b/usr.bin/rsh/rsh.c
index deea9d94990d..aecb81888e7c 100644
--- a/usr.bin/rsh/rsh.c
+++ b/usr.bin/rsh/rsh.c
@@ -269,10 +269,12 @@ try_connect:
} else {
if (doencrypt)
errx(1, "the -x flag requires Kerberos authentication");
- rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
+ rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args,
+ &rfd2, PF_UNSPEC);
}
#else
- rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
+ rem = rcmd_af(&host, sp->s_port, pw->pw_name, user, args, &rfd2,
+ PF_UNSPEC);
#endif
if (rem < 0)
diff --git a/usr.sbin/inetd/Makefile b/usr.sbin/inetd/Makefile
index 0df97554b47c..738bbed95283 100644
--- a/usr.sbin/inetd/Makefile
+++ b/usr.sbin/inetd/Makefile
@@ -10,7 +10,8 @@ MAINTAINER=des@freebsd.org
COPTS+= -Wall -DLOGIN_CAP
#COPTS+= -DSANITY_CHECK
-DPADD+= ${LIBUTIL} ${LIBWRAP}
-LDADD+= -lutil -lwrap
+CFLAGS+=-DINET6 -DIPSEC
+DPADD+= ${LIBUTIL} ${LIBWRAP} ${LIBIPSEC}
+LDADD+= -lutil -lwrap -lipsec
.include <bsd.prog.mk>
diff --git a/usr.sbin/inetd/builtins.c b/usr.sbin/inetd/builtins.c
index 6ba404c2a639..f05971fc0952 100644
--- a/usr.sbin/inetd/builtins.c
+++ b/usr.sbin/inetd/builtins.c
@@ -57,7 +57,7 @@ extern struct servtab *servtab;
char ring[128];
char *endring;
-int check_loop __P((struct sockaddr_in *, struct servtab *sep));
+int check_loop __P((struct sockaddr *, struct servtab *sep));
void inetd_setproctitle __P((char *, int));
struct biltin biltins[] = {
@@ -111,7 +111,7 @@ chargen_dg(s, sep) /* Character generator */
int s;
struct servtab *sep;
{
- struct sockaddr_in sin;
+ struct sockaddr_storage ss;
static char *rs;
int len, size;
char text[LINESIZ+2];
@@ -121,12 +121,12 @@ chargen_dg(s, sep) /* Character generator */
rs = ring;
}
- size = sizeof(sin);
+ size = sizeof(ss);
if (recvfrom(s, text, sizeof(text), 0,
- (struct sockaddr *)&sin, &size) < 0)
+ (struct sockaddr *)&ss, &size) < 0)
return;
- if (check_loop(&sin, sep))
+ if (check_loop((struct sockaddr *)&ss, sep))
return;
if ((len = endring - rs) >= LINESIZ)
@@ -140,7 +140,7 @@ chargen_dg(s, sep) /* Character generator */
text[LINESIZ] = '\r';
text[LINESIZ + 1] = '\n';
(void) sendto(s, text, sizeof(text), 0,
- (struct sockaddr *)&sin, sizeof(sin));
+ (struct sockaddr *)&ss, sizeof(ss));
}
/* ARGSUSED */
@@ -189,22 +189,22 @@ daytime_dg(s, sep) /* Return human-readable time of day */
{
char buffer[256];
time_t clock;
- struct sockaddr_in sin;
+ struct sockaddr_storage ss;
int size;
clock = time((time_t *) 0);
- size = sizeof(sin);
+ size = sizeof(ss);
if (recvfrom(s, buffer, sizeof(buffer), 0,
- (struct sockaddr *)&sin, &size) < 0)
+ (struct sockaddr *)&ss, &size) < 0)
return;
- if (check_loop(&sin, sep))
+ if (check_loop((struct sockaddr *)&ss, sep))
return;
(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
(void) sendto(s, buffer, strlen(buffer), 0,
- (struct sockaddr *)&sin, sizeof(sin));
+ (struct sockaddr *)&ss, sizeof(ss));
}
/* ARGSUSED */
@@ -270,18 +270,18 @@ echo_dg(s, sep) /* Echo service -- echo data back */
{
char buffer[BUFSIZE];
int i, size;
- struct sockaddr_in sin;
+ struct sockaddr_storage ss;
- size = sizeof(sin);
+ size = sizeof(ss);
if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
- (struct sockaddr *)&sin, &size)) < 0)
+ (struct sockaddr *)&ss, &size)) < 0)
return;
- if (check_loop(&sin, sep))
+ if (check_loop((struct sockaddr *)&ss, sep))
return;
- (void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin,
- sizeof(sin));
+ (void) sendto(s, buffer, i, 0, (struct sockaddr *)&ss,
+ sizeof(ss));
}
/* ARGSUSED */
@@ -335,6 +335,8 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
struct utsname un;
struct stat sb;
struct sockaddr_in sin[2];
+ struct sockaddr_in6 sin6[2];
+ struct sockaddr_storage ss[2];
struct ucred uc;
struct timeval tv = {
10,
@@ -345,7 +347,7 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
char buf[BUFSIZE], *cp = NULL, *p, **av, *osname = NULL, garbage[7];
char *fallback = NULL;
int len, c, fflag = 0, nflag = 0, rflag = 0, argc = 0, usedfallback = 0;
- int gflag = 0, Rflag = 0;
+ int gflag = 0, Rflag = 0, getcredfail = 0;
u_short lport, fport;
inetd_setproctitle(sep->se_service, s);
@@ -434,11 +436,11 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
iderror(0, 0, s, errno);
osname = un.sysname;
}
- len = sizeof(sin[0]);
- if (getsockname(s, (struct sockaddr *)&sin[0], &len) == -1)
+ len = sizeof(ss[0]);
+ if (getsockname(s, (struct sockaddr *)&ss[0], &len) == -1)
iderror(0, 0, s, errno);
- len = sizeof(sin[1]);
- if (getpeername(s, (struct sockaddr *)&sin[1], &len) == -1)
+ len = sizeof(ss[1]);
+ if (getpeername(s, (struct sockaddr *)&ss[1], &len) == -1)
iderror(0, 0, s, errno);
/*
* We're going to prepare for and execute reception of a
@@ -476,11 +478,35 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
* arrays have been filled in above via get{peer,sock}name(),
* so right here we are only setting the ports.
*/
- sin[0].sin_port = htons(lport);
- sin[1].sin_port = htons(fport);
+ if (ss[0].ss_family != ss[1].ss_family)
+ iderror(lport, fport, s, errno);
len = sizeof(uc);
- if (sysctlbyname("net.inet.tcp.getcred", &uc, &len, sin,
- sizeof(sin)) == -1) {
+ switch (ss[0].ss_family) {
+ case AF_INET:
+ sin[0] = *(struct sockaddr_in *)&ss[0];
+ sin[0].sin_port = htons(lport);
+ sin[1] = *(struct sockaddr_in *)&ss[1];
+ sin[1].sin_port = htons(fport);
+ if (sysctlbyname("net.inet.tcp.getcred", &uc, &len, sin,
+ sizeof(sin)) == -1)
+ getcredfail = 1;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ sin6[0] = *(struct sockaddr_in6 *)&ss[0];
+ sin6[0].sin6_port = htons(lport);
+ sin6[1] = *(struct sockaddr_in6 *)&ss[1];
+ sin6[1].sin6_port = htons(fport);
+ if (sysctlbyname("net.inet6.tcp6.getcred", &uc, &len, sin6,
+ sizeof(sin6)) == -1)
+ getcredfail = 1;
+ break;
+#endif
+ default: /* should not reach here */
+ getcredfail = 1;
+ break;
+ }
+ if (getcredfail != 0) {
if (fallback == NULL) /* Use a default, if asked to */
iderror(lport, fport, s, errno);
usedfallback = 1;
@@ -611,20 +637,20 @@ machtime_dg(s, sep)
struct servtab *sep;
{
unsigned long result;
- struct sockaddr_in sin;
+ struct sockaddr_storage ss;
int size;
- size = sizeof(sin);
+ size = sizeof(ss);
if (recvfrom(s, (char *)&result, sizeof(result), 0,
- (struct sockaddr *)&sin, &size) < 0)
+ (struct sockaddr *)&ss, &size) < 0)
return;
- if (check_loop(&sin, sep))
+ if (check_loop((struct sockaddr *)&ss, sep))
return;
result = machtime();
(void) sendto(s, (char *) &result, sizeof(result), 0,
- (struct sockaddr *)&sin, sizeof(sin));
+ (struct sockaddr *)&ss, sizeof(ss));
}
/* ARGSUSED */
diff --git a/usr.sbin/inetd/inetd.8 b/usr.sbin/inetd/inetd.8
index 2a3b411ba83f..66584d67387c 100644
--- a/usr.sbin/inetd/inetd.8
+++ b/usr.sbin/inetd/inetd.8
@@ -47,7 +47,7 @@
.Op Fl W
.Op Fl c Ar maximum
.Op Fl C Ar rate
-.Op Fl a Ar address
+.Op Fl a Ar address|hostname
.Op Fl p Ar filename
.Op Fl R Ar rate
.Op Ar configuration file
@@ -101,6 +101,22 @@ Specify the maximum number of times a service can be invoked
in one minute; the default is 256.
.It Fl a
Specify a specific IP address to bind to.
+Or a hostname can also be specified, and then an IP address and/or an
+IPv6 address corresponds to the hostname is used. Usually hostname
+specification is used in conjunction with
+.Xr jail 8 ,
+where the hostname corresponds to a jail environment.
+
+When hostname specification is used and either of IPv4 bind and IPv6
+bind is desired, you need to specify 2 entry for each service, one for
+IPv4 and one for IPv6, in /etc/inetd.conf.
+For example,
+.Bd -literal
+telnet stream tcp4 nowait root /usr/libexec/telnetd telnetd
+telnet stream tcp6 nowait root /usr/libexec/telnetd telnetd
+.Ed
+
+See explanation for protocol field in /etc/inetd.conf for details.
.It Fl p
Specify an alternate file in which to store the process ID.
.El
@@ -221,14 +237,39 @@ Examples might be
.Dq tcp
or
.Dq udp .
+In this case, this entry only accept IPv4 to keep backword
+compatibility.
+The names
+.Dq tcp4 ,
+.Dq udp4
+specialized the entry to IPv4 only.
+The names
+.Dq tcp6 ,
+.Dq udp6
+specialized the entry to IPv6 only.
+The names
+.Dq tcp46 ,
+.Dq udp46
+let the entry accept each of IPv4 and IPv6 via AF_INET6 wildcard binded socket.
If it is desired that the service is reachable via T/TCP, one should
specify
.Dq tcp/ttcp .
+This entry only accept IPv4 to keep backword compatibility.
+The name
+.Dq tcp4/ttcp ,
+specialized the entry to IPv4 only.
+The name
+.Dq tcp6/ttcp ,
+specialized the entry to IPv6 only.
+The name
+.Dq tcp46/ttcp ,
+let the entry accept each of IPv4 and IPv6 via AF_INET6 wildcard binded socket.
Rpc based services are specified with the
.Dq rpc/tcp
or
.Dq rpc/udp
service type.
+Currently only IPv4 is supported for rpc services.
TCPMUX services must use
.Dq tcp .
.Pp
@@ -436,6 +477,9 @@ in
tcpmux stream tcp nowait root internal
.Ed
.Pp
+Or if you wish to provide TCPMUX services also over IPv6, you can
+specify tcp46 or tcp6 instead of tcp above.
+.Pp
When given the
.Fl l
option
@@ -528,6 +572,30 @@ causes
.Nm
to list TCPMUX services in
.Pa inetd.conf .
+.Sh IPSEC
+The implementation includes tiny hack to support IPsec policy setting for
+each of the socket.
+A special form of comment line, starting with
+.Dq Li "#@" ,
+will work as policy specifier.
+The content of the above comment line will be treated as IPsec policy string,
+as described in
+.Xr ipsec_set_policy 3 .
+A
+.Li "#@"
+line will affect all the following lines in
+.Pa inetd.conf ,
+so you may want to reset IPsec policy by using a comment line with
+.Li "#@"
+only
+.Pq with no policy string .
+.Pp
+If invalid IPsec policy string appears on
+.Pa inetd.conf ,
+.Nm
+will leave error message using
+.Xr syslog 3 ,
+and terminates itself.
.Sh "FILES"
.Bl -tag -width /var/run/inetd.pid -compact
.It Pa /etc/inetd.conf
@@ -546,9 +614,14 @@ Here are several example service entries for the various types of services:
.Bd -literal
ftp stream tcp nowait root /usr/libexec/ftpd ftpd -l
ntalk dgram udp wait root /usr/libexec/ntalkd ntalkd
+telnet stream tcp6 nowait root /usr/libexec/telnetd telnetd
+shell stream tcp46 nowait root /usr/libexec/rshd rshd
tcpmux/+date stream tcp nowait guest /bin/date date
tcpmux/phonebook stream tcp nowait guest /usr/local/bin/phonebook phonebook
rstatd/1-3 dgram rpc/udp wait root /usr/libexec/rpc.rstatd rpc.rstatd
+#@ ipsec ah/require
+chargen stream tcp nowait root internal
+#@
.Ed
.Sh "ERROR MESSAGES"
The
@@ -632,6 +705,7 @@ socket but was unable to.
.Sh SEE ALSO
.Xr hosts_access 5 ,
.Xr hosts_options 5 ,
+.Xr ipsec_set_policy 3 ,
.Xr login.conf 5 ,
.Xr passwd 5 ,
.Xr rpc 5 ,
@@ -662,6 +736,7 @@ based services is modeled after that
provided by
.Tn SunOS
4.1.
+IPsec hack was made by KAME project, in 1999.
The
.Tn FreeBSD
TCP Wrappers support first appeared in
diff --git a/usr.sbin/inetd/inetd.c b/usr.sbin/inetd/inetd.c
index 33787536978d..06bad40e8f0d 100644
--- a/usr.sbin/inetd/inetd.c
+++ b/usr.sbin/inetd/inetd.c
@@ -102,6 +102,13 @@ static const char rcsid[] =
* server program arguments maximum of MAXARGS
*
* Comment lines are indicated by a `#' in column 1.
+ *
+ * #ifdef IPSEC
+ * Comment lines that start with "#@" denote IPsec policy string, as described
+ * in ipsec_set_policy(3). This will affect all the following items in
+ * inetd.conf(8). To reset the policy, just use "#@" line. By default,
+ * there's no IPsec policy.
+ * #endif
*/
#include <sys/param.h>
#include <sys/ioctl.h>
@@ -130,10 +137,23 @@ static const char rcsid[] =
#include <unistd.h>
#include <libutil.h>
#include <sysexits.h>
+#include <ctype.h>
#include "inetd.h"
#include "pathnames.h"
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#ifndef IPSEC_POLICY_IPSEC /* no ipsec support on old ipsec */
+#undef IPSEC
+#endif
+#endif
+
+/* wrapper for KAME-special getnameinfo() */
+#ifndef NI_WITHSCOPEID
+#define NI_WITHSCOPEID 0
+#endif
+
#ifndef LIBWRAP_ALLOW_FACILITY
# define LIBWRAP_ALLOW_FACILITY LOG_AUTH
#endif
@@ -193,7 +213,13 @@ int maxchild = MAXCHILD;
int maxcpm = MAXCPM;
struct servent *sp;
struct rpcent *rpc;
-struct in_addr bind_address;
+char *hostname = NULL;
+struct sockaddr_in *bind_sa4;
+int no_v4bind = 1;
+#ifdef INET6
+struct sockaddr_in6 *bind_sa6;
+int no_v6bind = 1;
+#endif
int signalpipe[2];
#ifdef SANITY_CHECK
int nsock;
@@ -248,8 +274,20 @@ main(argc, argv, envp)
int denied;
char *service = NULL;
char *pnm;
- struct sockaddr_in peer;
+ union {
+ struct sockaddr peer_un;
+ struct sockaddr_in peer_un4;
+ struct sockaddr_in6 peer_un6;
+ struct sockaddr_storage peer_max;
+ } p_un;
+#define peer p_un.peer_un
+#define peer4 p_un.peer_un4
+#define peer6 p_un.peer_un6
+#define peermax p_un.peer_max
int i;
+ struct addrinfo hints, *res;
+ char *servname;
+ int error;
#ifdef OLD_SETPROCTITLE
@@ -263,7 +301,6 @@ main(argc, argv, envp)
openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
- bind_address.s_addr = htonl(INADDR_ANY);
while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:")) != -1)
switch(ch) {
case 'd':
@@ -286,11 +323,7 @@ main(argc, argv, envp)
"-C %s: bad value for maximum children/minute");
break;
case 'a':
- if (!inet_aton(optarg, &bind_address)) {
- syslog(LOG_ERR,
- "-a %s: invalid IP address", optarg);
- exit(EX_USAGE);
- }
+ hostname = optarg;
break;
case 'p':
pid_file = optarg;
@@ -309,6 +342,66 @@ main(argc, argv, envp)
" [-p pidfile] [conf-file]");
exit(EX_USAGE);
}
+ /*
+ * Initialize Bind Addrs.
+ * When hostname is NULL, wild card bind addrs are obtained from
+ * getaddrinfo(). But getaddrinfo() requires at least one of
+ * hostname or servname is non NULL.
+ * So when hostname is NULL, set dummy value to servname.
+ */
+ servname = (hostname == NULL) ? "discard" /* dummy */ : NULL;
+
+ bzero(&hints, sizeof(struct addrinfo));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = AF_UNSPEC;
+ error = getaddrinfo(hostname, servname, &hints, &res);
+ if (error != 0) {
+ syslog(LOG_ERR, "-a %s: %s", hostname, gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ syslog(LOG_ERR, "%s", strerror(errno));
+ exit(EX_USAGE);
+ }
+ do {
+ if (res->ai_addr == NULL) {
+ syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname);
+ exit(EX_USAGE);
+ }
+ switch (res->ai_addr->sa_family) {
+ case AF_INET:
+ if (no_v4bind == 0)
+ continue;
+ bind_sa4 = (struct sockaddr_in *)res->ai_addr;
+ /* init port num in case servname is dummy */
+ bind_sa4->sin_port = 0;
+ no_v4bind = 0;
+ continue;
+#ifdef INET6
+ case AF_INET6:
+ if (no_v6bind == 0)
+ continue;
+ bind_sa6 = (struct sockaddr_in6 *)res->ai_addr;
+ /* init port num in case servname is dummy */
+ bind_sa6->sin6_port = 0;
+ no_v6bind = 0;
+ continue;
+#endif
+ }
+ if (no_v4bind == 0
+#ifdef INET6
+ && no_v6bind == 0
+#endif
+ )
+ break;
+ } while ((res = res->ai_next) != NULL);
+ if (no_v4bind != 0
+#ifdef INET6
+ && no_v6bind != 0
+#endif
+ ) {
+ syslog(LOG_ERR, "-a %s: unknown address family", hostname);
+ exit(EX_USAGE);
+ }
+
argc -= optind;
argv += optind;
@@ -457,18 +550,33 @@ main(argc, argv, envp)
} else
ctrl = sep->se_fd;
if (log && !ISWRAP(sep)) {
+ char pname[INET6_ADDRSTRLEN];
pnm = "unknown";
- i = sizeof peer;
+ i = sizeof peermax;
if (getpeername(ctrl, (struct sockaddr *)
- &peer, &i)) {
- i = sizeof peer;
+ &peermax, &i)) {
+ i = sizeof peermax;
if (recvfrom(ctrl, buf, sizeof(buf),
MSG_PEEK,
- (struct sockaddr *)&peer, &i) >= 0)
- pnm = inet_ntoa(peer.sin_addr);
+ (struct sockaddr *)&peermax,
+ &i) >= 0) {
+ getnameinfo((struct sockaddr *)&peermax,
+ sizeof(peermax),
+ pname, sizeof(pname),
+ NULL, 0,
+ NI_NUMERICHOST|
+ NI_WITHSCOPEID);
+ pnm = pname;
+ }
+ } else {
+ getnameinfo((struct sockaddr *)&peermax,
+ sizeof(peermax),
+ pname, sizeof(pname),
+ NULL, 0,
+ NI_NUMERICHOST|
+ NI_WITHSCOPEID);
+ pnm = pname;
}
- else
- pnm = inet_ntoa(peer.sin_addr);
syslog(LOG_INFO,"%s from %s", sep->se_service, pnm);
}
(void) sigblock(SIGBLOCK);
@@ -783,13 +891,18 @@ void config()
#endif
for (sep = servtab; sep; sep = sep->se_next)
if (strcmp(sep->se_service, new->se_service) == 0 &&
- strcmp(sep->se_proto, new->se_proto) == 0)
+ strcmp(sep->se_proto, new->se_proto) == 0 &&
+ sep->se_family == new->se_family)
break;
if (sep != 0) {
int i;
#define SWAP(a, b) { typeof(a) c = a; a = b; b = c; }
omask = sigblock(SIGBLOCK);
+ if (sep->se_nomapped != new->se_nomapped) {
+ sep->se_nomapped = new->se_nomapped;
+ sep->se_reset = 1;
+ }
/* copy over outstanding child pids */
if (sep->se_maxchild && new->se_maxchild) {
new->se_numchild = sep->se_numchild;
@@ -823,6 +936,10 @@ void config()
SWAP(sep->se_server_name, new->se_server_name);
for (i = 0; i < MAXARGV; i++)
SWAP(sep->se_argv[i], new->se_argv[i]);
+#ifdef IPSEC
+ SWAP(sep->se_policy, new->se_policy);
+ ipsecsetup(sep);
+#endif
sigsetmask(omask);
freeconfig(new);
if (debug)
@@ -837,21 +954,63 @@ void config()
sep->se_fd = -1;
continue;
}
+ switch (sep->se_family) {
+ case AF_INET:
+ if (no_v4bind != 0) {
+ sep->se_fd = -1;
+ continue;
+ }
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (no_v6bind != 0) {
+ sep->se_fd = -1;
+ continue;
+ }
+ break;
+#endif
+ }
if (!sep->se_rpc) {
sp = getservbyname(sep->se_service, sep->se_proto);
if (sp == 0) {
syslog(LOG_ERR, "%s/%s: unknown service",
- sep->se_service, sep->se_proto);
+ sep->se_service, sep->se_proto);
sep->se_checked = 0;
continue;
}
- if (sp->s_port != sep->se_ctrladdr.sin_port) {
- sep->se_ctrladdr.sin_family = AF_INET;
- sep->se_ctrladdr.sin_addr = bind_address;
- sep->se_ctrladdr.sin_port = sp->s_port;
- if (sep->se_fd >= 0)
- close_sep(sep);
+ switch (sep->se_family) {
+ case AF_INET:
+ if (sep->se_ctladdrinitok == 0) {
+ memcpy(&sep->se_ctrladdr4, bind_sa4,
+ sizeof(sep->se_ctrladdr4));
+ sep->se_ctrladdr_size =
+ sizeof(sep->se_ctrladdr4);
+ }
+ if (sp->s_port != sep->se_ctrladdr4.sin_port) {
+ sep->se_ctrladdr4.sin_port =
+ sp->s_port;
+ sep->se_reset = 1;
+ }
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (sep->se_ctladdrinitok == 0) {
+ memcpy(&sep->se_ctrladdr6, bind_sa6,
+ sizeof(sep->se_ctrladdr6));
+ sep->se_ctrladdr_size =
+ sizeof(sep->se_ctrladdr6);
+ }
+ if (sp->s_port !=
+ sep->se_ctrladdr6.sin6_port) {
+ sep->se_ctrladdr6.sin6_port =
+ sp->s_port;
+ sep->se_reset = 1;
+ }
+ break;
+#endif
}
+ if (sep->se_reset != 0 && sep->se_fd >= 0)
+ close_sep(sep);
} else {
rpc = getrpcbyname(sep->se_service);
if (rpc == 0) {
@@ -950,7 +1109,7 @@ setup(sep)
{
int on = 1;
- if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
+ if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
if (debug)
warn("socket failed on %s/%s",
sep->se_service, sep->se_proto);
@@ -969,13 +1128,38 @@ setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
if (turnon(sep->se_fd, SO_PRIVSTATE) < 0)
syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m");
#endif
+ /* tftpd opens a new connection then needs more infos */
+ if ((sep->se_family == AF_INET6) &&
+ (strcmp(sep->se_proto, "udp") == 0) &&
+ (sep->se_accept == 0) &&
+ (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_PKTINFO,
+ (char *)&on, sizeof (on)) < 0))
+ syslog(LOG_ERR, "setsockopt (IPV6_RECVPKTINFO): %m");
+#ifdef IPV6_BINDV6ONLY
+ if ((sep->se_family == AF_INET6) &&
+ (sep->se_nomapped != 0) &&
+ (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_BINDV6ONLY,
+ (char *)&on, sizeof (on)) < 0))
+ syslog(LOG_ERR, "setsockopt (IPV6_BINDV6ONLY): %m");
+#endif /* IPV6_BINDV6ONLY */
#undef turnon
if (sep->se_type == TTCP_TYPE)
if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH,
(char *)&on, sizeof (on)) < 0)
syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m");
+#ifdef IPV6_FAITH
+ if (sep->se_type == FAITH_TYPE) {
+ if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH, &on,
+ sizeof(on)) < 0) {
+ syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m");
+ }
+ }
+#endif
+#ifdef IPSEC
+ ipsecsetup(sep);
+#endif
if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
- sizeof (sep->se_ctrladdr)) < 0) {
+ sep->se_ctrladdr_size) < 0) {
if (debug)
warn("bind failed on %s/%s",
sep->se_service, sep->se_proto);
@@ -990,8 +1174,16 @@ setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
return;
}
if (sep->se_rpc) {
- int i, len = sizeof(struct sockaddr);
+ int i, len = sep->se_ctrladdr_size;
+ if (sep->se_family != AF_INET) {
+ syslog(LOG_ERR,
+ "%s/%s: unsupported address family for rpc",
+ sep->se_service, sep->se_proto);
+ (void) close(sep->se_fd);
+ sep->se_fd = -1;
+ return;
+ }
if (getsockname(sep->se_fd,
(struct sockaddr*)&sep->se_ctrladdr, &len) < 0){
syslog(LOG_ERR, "%s/%s: getsockname: %m",
@@ -1007,9 +1199,8 @@ setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
pmap_set(sep->se_rpc_prog, i,
(sep->se_socktype == SOCK_DGRAM)
? IPPROTO_UDP : IPPROTO_TCP,
- ntohs(sep->se_ctrladdr.sin_port));
+ ntohs(sep->se_ctrladdr4.sin_port));
}
-
}
if (sep->se_socktype == SOCK_STREAM)
listen(sep->se_fd, 64);
@@ -1020,6 +1211,80 @@ setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
}
}
+#ifdef IPSEC
+void
+ipsecsetup(sep)
+ struct servtab *sep;
+{
+ char *buf;
+ char *policy_in = NULL;
+ char *policy_out = NULL;
+ int level;
+ int opt;
+
+ switch (sep->se_family) {
+ case AF_INET:
+ level = IPPROTO_IP;
+ opt = IP_IPSEC_POLICY;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ level = IPPROTO_IPV6;
+ opt = IPV6_IPSEC_POLICY;
+ break;
+#endif
+ default:
+ return;
+ }
+
+ if (!sep->se_policy || sep->se_policy[0] == '\0') {
+ policy_in = "in entrust";
+ policy_out = "out entrust";
+ } else {
+ if (!strncmp("in", sep->se_policy, 2))
+ policy_in = sep->se_policy;
+ else if (!strncmp("out", sep->se_policy, 3))
+ policy_out = sep->se_policy;
+ else {
+ syslog(LOG_ERR, "invalid security policy \"%s\"",
+ sep->se_policy);
+ return;
+ }
+ }
+
+ if (policy_in != NULL) {
+ buf = ipsec_set_policy(policy_in, strlen(policy_in));
+ if (buf != NULL) {
+ if (setsockopt(sep->se_fd, level, opt,
+ buf, ipsec_get_policylen(buf)) < 0) {
+ syslog(LOG_ERR,
+ "%s/%s: ipsec initialization failed; %s",
+ sep->se_service, sep->se_proto,
+ policy_in);
+ }
+ free(buf);
+ } else
+ syslog(LOG_ERR, "invalid security policy \"%s\"",
+ policy_in);
+ }
+ if (policy_out != NULL) {
+ buf = ipsec_set_policy(policy_out, strlen(policy_out));
+ if (buf != NULL) {
+ if (setsockopt(sep->se_fd, level, opt,
+ buf, ipsec_get_policylen(buf)) < 0) {
+ syslog(LOG_ERR,
+ "%s/%s: ipsec initialization failed; %s",
+ sep->se_service, sep->se_proto,
+ policy_out);
+ }
+ free(buf);
+ } else
+ syslog(LOG_ERR, "invalid security policy \"%s\"",
+ policy_out);
+ }
+}
+#endif
+
/*
* Finish with a service and its socket.
*/
@@ -1173,10 +1438,42 @@ getconfigent()
char *versp;
static char TCPMUX_TOKEN[] = "tcpmux/";
#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1)
+#ifdef IPSEC
+ char *policy = NULL;
+#endif
+ int v4bind = 0;
+#ifdef INET6
+ int v6bind = 0;
+#endif
more:
- while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
- ;
+ while ((cp = nextline(fconfig)) != NULL) {
+#ifdef IPSEC
+ /* lines starting with #@ is not a comment, but the policy */
+ if (cp[0] == '#' && cp[1] == '@') {
+ char *p;
+ for (p = cp + 2; p && *p && isspace(*p); p++)
+ ;
+ if (*p == '\0') {
+ if (policy)
+ free(policy);
+ policy = NULL;
+ } else if (ipsec_get_policylen(p) >= 0) {
+ if (policy)
+ free(policy);
+ policy = newstr(p);
+ } else {
+ syslog(LOG_ERR,
+ "%s: invalid ipsec policy \"%s\"",
+ CONFIG, p);
+ exit(EX_CONFIG);
+ }
+ }
+#endif
+ if (*cp == '#' || *cp == '\0')
+ continue;
+ break;
+ }
if (cp == NULL)
return ((struct servtab *)0);
/*
@@ -1216,21 +1513,29 @@ more:
sep->se_socktype = -1;
arg = sskip(&cp);
- if (strcmp(arg, "tcp/ttcp") == 0) {
- sep->se_type = TTCP_TYPE;
- sep->se_proto = newstr("tcp");
- } else {
+ if (strncmp(arg, "tcp", 3) == 0) {
+ sep->se_proto = newstr(strsep(&arg, "/"));
+ if (arg != NULL) {
+ if (strcmp(arg, "ttcp") == 0)
+ sep->se_type = TTCP_TYPE;
+ else if (strcmp(arg, "faith") == 0)
+ sep->se_type = FAITH_TYPE;
+ }
+ } else
sep->se_proto = newstr(arg);
- }
if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
+ if (sep->se_family != AF_INET) {
+ syslog(LOG_ERR, "IPv6 for RPC is not supported yet");
+ freeconfig(sep);
+ goto more;
+ }
memmove(sep->se_proto, sep->se_proto + 4,
strlen(sep->se_proto) + 1 - 4);
sep->se_rpc = 1;
sep->se_rpc_prog = sep->se_rpc_lowvers =
sep->se_rpc_lowvers = 0;
- sep->se_ctrladdr.sin_family = AF_INET;
- sep->se_ctrladdr.sin_port = 0;
- sep->se_ctrladdr.sin_addr = bind_address;
+ memcpy(&sep->se_ctrladdr4, bind_sa4,
+ sizeof(sep->se_ctrladdr4));
if ((versp = rindex(sep->se_service, '/'))) {
*versp++ = '\0';
switch (sscanf(versp, "%d-%d",
@@ -1255,6 +1560,64 @@ more:
sep->se_rpc_highvers = 1;
}
}
+ sep->se_nomapped = 0;
+ while (isdigit(sep->se_proto[strlen(sep->se_proto) - 1])) {
+#ifdef INET6
+ if (sep->se_proto[strlen(sep->se_proto) - 1] == '6') {
+ if (no_v6bind != 0) {
+ syslog(LOG_INFO, "IPv6 bind is ignored for %s",
+ sep->se_service);
+ freeconfig(sep);
+ goto more;
+ }
+ sep->se_proto[strlen(sep->se_proto) - 1] = '\0';
+ v6bind = 1;
+ continue;
+ }
+#endif
+ if (sep->se_proto[strlen(sep->se_proto) - 1] == '4') {
+ sep->se_proto[strlen(sep->se_proto) - 1] = '\0';
+ v4bind = 1;
+ continue;
+ }
+ /* illegal version num */
+ syslog(LOG_ERR, "bad IP version for %s", sep->se_proto);
+ freeconfig(sep);
+ goto more;
+ }
+#ifdef INET6
+ if (v6bind != 0) {
+ sep->se_family = AF_INET6;
+ if (v4bind == 0 || no_v4bind != 0)
+ sep->se_nomapped = 1;
+ }
+#endif
+ else { /* default to v4 bind if not v6 bind */
+ if (no_v4bind != 0) {
+ syslog(LOG_INFO, "IPv4 bind is ignored for %s",
+ sep->se_service);
+ freeconfig(sep);
+ goto more;
+ }
+ sep->se_family = AF_INET;
+ }
+ /* init ctladdr */
+ switch(sep->se_family) {
+ case AF_INET:
+ memcpy(&sep->se_ctrladdr4, bind_sa4,
+ sizeof(sep->se_ctrladdr4));
+ sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr4);
+ sep->se_ctladdrinitok = 1;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ memcpy(&sep->se_ctrladdr6, bind_sa6,
+ sizeof(sep->se_ctrladdr6));
+ sep->se_ctrladdr_size = sizeof(sep->se_ctrladdr6);
+ sep->se_ctladdrinitok = 1;
+ break;
+#endif
+ }
arg = sskip(&cp);
if (!strncmp(arg, "wait", 4))
sep->se_accept = 0;
@@ -1372,6 +1735,9 @@ more:
}
while (argc <= MAXARGV)
sep->se_argv[argc++] = NULL;
+#ifdef IPSEC
+ sep->se_policy = policy ? newstr(policy) : NULL;
+#endif
return (sep);
}
@@ -1400,6 +1766,10 @@ freeconfig(cp)
for (i = 0; i < MAXARGV; i++)
if (cp->se_argv[i])
free(cp->se_argv[i]);
+#ifdef IPSEC
+ if (cp->se_policy)
+ free(cp->se_policy);
+#endif
}
@@ -1490,14 +1860,16 @@ inetd_setproctitle(a, s)
{
int size;
char *cp;
- struct sockaddr_in sin;
- char buf[80];
+ struct sockaddr_storage ss;
+ char buf[80], pbuf[INET6_ADDRSTRLEN];
cp = Argv[0];
- size = sizeof(sin);
- if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
- (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
- else
+ size = sizeof(ss);
+ if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
+ getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf),
+ NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID);
+ (void) sprintf(buf, "-%s [%s]", a, pbuf);
+ } else
(void) sprintf(buf, "-%s", a);
strncpy(cp, buf, LastArg - cp);
cp += strlen(cp);
@@ -1511,13 +1883,15 @@ inetd_setproctitle(a, s)
int s;
{
int size;
- struct sockaddr_in sin;
- char buf[80];
-
- size = sizeof(sin);
- if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
- (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr));
- else
+ struct sockaddr_storage ss;
+ char buf[80], pbuf[INET6_ADDRSTRLEN];
+
+ size = sizeof(ss);
+ if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
+ getnameinfo((struct sockaddr *)&ss, size, pbuf, sizeof(pbuf),
+ NULL, 0, NI_NUMERICHOST|NI_WITHSCOPEID);
+ (void) sprintf(buf, "%s [%s]", a, pbuf);
+ } else
(void) sprintf(buf, "%s", a);
setproctitle("%s", buf);
}
@@ -1528,24 +1902,41 @@ inetd_setproctitle(a, s)
* Internet services provided internally by inetd:
*/
-int check_loop(sin, sep)
- struct sockaddr_in *sin;
+int check_loop(sa, sep)
+ struct sockaddr *sa;
struct servtab *sep;
{
struct servtab *se2;
+ char pname[INET6_ADDRSTRLEN];
for (se2 = servtab; se2; se2 = se2->se_next) {
if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM)
continue;
- if (sin->sin_port == se2->se_ctrladdr.sin_port) {
- syslog(LOG_WARNING,
- "%s/%s:%s/%s loop request REFUSED from %s",
- sep->se_service, sep->se_proto,
- se2->se_service, se2->se_proto,
- inet_ntoa(sin->sin_addr));
- return 1;
+ switch (se2->se_family) {
+ case AF_INET:
+ if (((struct sockaddr_in *)sa)->sin_port ==
+ se2->se_ctrladdr4.sin_port)
+ goto isloop;
+ continue;
+#ifdef INET6
+ case AF_INET6:
+ if (((struct sockaddr_in *)sa)->sin_port ==
+ se2->se_ctrladdr4.sin_port)
+ goto isloop;
+ continue;
+#endif
+ default:
+ continue;
}
+ isloop:
+ getnameinfo(sa, sa->sa_len, pname, sizeof(pname), NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
+ syslog(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s",
+ sep->se_service, sep->se_proto,
+ se2->se_service, se2->se_proto,
+ pname);
+ return 1;
}
return 0;
}
@@ -1560,17 +1951,25 @@ print_service(action, sep)
struct servtab *sep;
{
fprintf(stderr,
+ "%s: %s proto=%s accept=%d max=%d user=%s group=%s"
#ifdef LOGIN_CAP
- "%s: %s proto=%s accept=%d max=%d user=%s group=%s class=%s builtin=%p server=%s\n",
-#else
- "%s: %s proto=%s accept=%d max=%d user=%s group=%s builtin=%p server=%s\n",
+ "class=%s"
+#endif
+ " builtin=%p server=%s"
+#ifdef IPSEC
+ " policy=\"%s\""
#endif
+ "\n",
action, sep->se_service, sep->se_proto,
sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group,
#ifdef LOGIN_CAP
sep->se_class,
#endif
- (void *) sep->se_bi, sep->se_server);
+ (void *) sep->se_bi, sep->se_server
+#ifdef IPSEC
+ , (sep->se_policy ? sep->se_policy : "")
+#endif
+ );
}
#define CPMHSIZE 256
@@ -1584,7 +1983,13 @@ typedef struct CTime {
} CTime;
typedef struct CHash {
- struct in_addr ch_Addr;
+ union {
+ struct in_addr c4_Addr;
+ struct in6_addr c6_Addr;
+ } cu_Addr;
+#define ch_Addr4 cu_Addr.c4_Addr
+#define ch_Addr6 cu_Addr.c6_Addr
+ int ch_Family;
time_t ch_LTime;
char *ch_Service;
CTime ch_Times[CHTSIZE];
@@ -1597,8 +2002,8 @@ cpmip(sep, ctrl)
struct servtab *sep;
int ctrl;
{
- struct sockaddr_in rsin;
- int rsinLen = sizeof(rsin);
+ struct sockaddr_storage rss;
+ int rssLen = sizeof(rss);
int r = 0;
/*
@@ -1607,21 +2012,43 @@ cpmip(sep, ctrl)
*/
if (sep->se_maxcpm > 0 &&
- getpeername(ctrl, (struct sockaddr *)&rsin, &rsinLen) == 0 ) {
+ getpeername(ctrl, (struct sockaddr *)&rss, &rssLen) == 0 ) {
time_t t = time(NULL);
int hv = 0xABC3D20F;
int i;
int cnt = 0;
CHash *chBest = NULL;
unsigned int ticks = t / CHTGRAN;
+ struct sockaddr_in *sin;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
+ sin = (struct sockaddr_in *)&rss;
+#ifdef INET6
+ sin6 = (struct sockaddr_in6 *)&rss;
+#endif
{
char *p;
- int i;
+ int i, addrlen;
- for (i = 0, p = (char *)&rsin.sin_addr;
- i < sizeof(rsin.sin_addr);
- ++i, ++p) {
+ switch (rss.ss_family) {
+ case AF_INET:
+ p = (char *)&sin->sin_addr;
+ addrlen = sizeof(struct in_addr);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ p = (char *)&sin6->sin6_addr;
+ addrlen = sizeof(struct in6_addr);
+ break;
+#endif
+ default:
+ /* should not happen */
+ return -1;
+ }
+
+ for (i = 0; i < addrlen; ++i, ++p) {
hv = (hv << 5) ^ (hv >> 23) ^ *p;
}
hv = (hv ^ (hv >> 16));
@@ -1629,26 +2056,57 @@ cpmip(sep, ctrl)
for (i = 0; i < 5; ++i) {
CHash *ch = &CHashAry[(hv + i) & CPMHMASK];
- if (rsin.sin_addr.s_addr == ch->ch_Addr.s_addr &&
+ if (rss.ss_family == AF_INET &&
+ ch->ch_Family == AF_INET &&
+ sin->sin_addr.s_addr == ch->ch_Addr4.s_addr &&
ch->ch_Service && strcmp(sep->se_service,
ch->ch_Service) == 0) {
chBest = ch;
break;
}
+#ifdef INET6
+ if (rss.ss_family == AF_INET6 &&
+ ch->ch_Family == AF_INET6 &&
+ IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
+ &ch->ch_Addr6) != 0 &&
+ ch->ch_Service && strcmp(sep->se_service,
+ ch->ch_Service) == 0) {
+ chBest = ch;
+ break;
+ }
+#endif
if (chBest == NULL || ch->ch_LTime == 0 ||
ch->ch_LTime < chBest->ch_LTime) {
chBest = ch;
}
}
- if (rsin.sin_addr.s_addr != chBest->ch_Addr.s_addr ||
+ if ((rss.ss_family == AF_INET &&
+ (chBest->ch_Family != AF_INET ||
+ sin->sin_addr.s_addr != chBest->ch_Addr4.s_addr)) ||
chBest->ch_Service == NULL ||
strcmp(sep->se_service, chBest->ch_Service) != 0) {
- chBest->ch_Addr = rsin.sin_addr;
+ chBest->ch_Family = sin->sin_family;
+ chBest->ch_Addr4 = sin->sin_addr;
if (chBest->ch_Service)
free(chBest->ch_Service);
chBest->ch_Service = strdup(sep->se_service);
bzero(chBest->ch_Times, sizeof(chBest->ch_Times));
}
+#ifdef INET6
+ if ((rss.ss_family == AF_INET6 &&
+ (chBest->ch_Family != AF_INET6 ||
+ IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
+ &chBest->ch_Addr6) == 0)) ||
+ chBest->ch_Service == NULL ||
+ strcmp(sep->se_service, chBest->ch_Service) != 0) {
+ chBest->ch_Family = sin6->sin6_family;
+ chBest->ch_Addr6 = sin6->sin6_addr;
+ if (chBest->ch_Service)
+ free(chBest->ch_Service);
+ chBest->ch_Service = strdup(sep->se_service);
+ bzero(chBest->ch_Times, sizeof(chBest->ch_Times));
+ }
+#endif
chBest->ch_LTime = t;
{
CTime *ct = &chBest->ch_Times[ticks % CHTSIZE];
@@ -1666,10 +2124,16 @@ cpmip(sep, ctrl)
}
}
if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) {
+ char pname[INET6_ADDRSTRLEN];
+
+ getnameinfo((struct sockaddr *)&rss,
+ ((struct sockaddr *)&rss)->sa_len,
+ pname, sizeof(pname), NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
r = -1;
syslog(LOG_ERR,
"%s from %s exceeded counts/min (limit %d/min)",
- sep->se_service, inet_ntoa(rsin.sin_addr),
+ sep->se_service, pname,
sep->se_maxcpm);
}
}
diff --git a/usr.sbin/inetd/inetd.h b/usr.sbin/inetd/inetd.h
index ab78c734c54e..f956c1a8669e 100644
--- a/usr.sbin/inetd/inetd.h
+++ b/usr.sbin/inetd/inetd.h
@@ -47,6 +47,7 @@
#define MUX_TYPE 1
#define MUXPLUS_TYPE 2
#define TTCP_TYPE 3
+#define FAITH_TYPE 4
#define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \
((sep)->se_type == MUXPLUS_TYPE))
#define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE)
@@ -55,6 +56,7 @@
struct servtab {
char *se_service; /* name of service */
int se_socktype; /* type of socket to use */
+ int se_family; /* address family */
char *se_proto; /* protocol used */
int se_maxchild; /* max number of children */
int se_maxcpm; /* max connects per IP per minute */
@@ -70,8 +72,19 @@ struct servtab {
char *se_server_name; /* server program without path */
#define MAXARGV 20
char *se_argv[MAXARGV+1]; /* program arguments */
+#ifdef IPSEC
+ char *se_policy; /* IPsec poilcy string */
+#endif
int se_fd; /* open descriptor */
- struct sockaddr_in se_ctrladdr;/* bound address */
+ union { /* bound address */
+ struct sockaddr se_un_ctrladdr;
+ struct sockaddr_in se_un_ctrladdr4;
+ struct sockaddr_in6 se_un_ctrladdr6;
+ } se_un;
+#define se_ctrladdr se_un.se_un_ctrladdr
+#define se_ctrladdr4 se_un.se_un_ctrladdr4
+#define se_ctrladdr6 se_un.se_un_ctrladdr6
+ int se_ctrladdr_size;
u_char se_type; /* type: normal, mux, or mux+ */
u_char se_checked; /* looked at during merge */
u_char se_accept; /* i.e., wait/nowait mode */
@@ -82,8 +95,17 @@ struct servtab {
int se_count; /* number started since se_time */
struct timeval se_time; /* start of se_count */
struct servtab *se_next;
+ struct se_flags {
+ u_int se_nomapped : 1;
+ u_int se_ctladdrinitok : 1;
+ u_int se_reset : 1;
+ } se_flags;
};
+#define se_nomapped se_flags.se_nomapped
+#define se_ctladdrinitok se_flags.se_ctladdrinitok
+#define se_reset se_flags.se_reset
+
void chargen_dg __P((int, struct servtab *));
void chargen_stream __P((int, struct servtab *));
void close_sep __P((struct servtab *));
@@ -117,6 +139,9 @@ void flag_retry __P((int));
void retry __P((void));
int setconfig __P((void));
void setup __P((struct servtab *));
+#ifdef IPSEC
+void ipsecsetup __P((struct servtab *));
+#endif
char *sskip __P((char **));
char *skip __P((char **));
struct servtab *tcpmux __P((int));