summaryrefslogtreecommitdiff
path: root/usr.sbin/faithd
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2001-02-15 17:37:34 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2001-02-15 17:37:34 +0000
commitbd74ca448b83994d40bb8b97d267863785e098a6 (patch)
tree76b1d97cd8ff19f539ac406c7090ffc2d9ed2b5c /usr.sbin/faithd
parente67e266e4982c344ac308ec37afc140fdfebe986 (diff)
pull latest KAME faithd. access control is possible by /etc/faithd.conf.
req'ed by todd
Diffstat (limited to 'usr.sbin/faithd')
-rw-r--r--usr.sbin/faithd/Makefile4
-rw-r--r--usr.sbin/faithd/faithd.8120
-rw-r--r--usr.sbin/faithd/faithd.c108
-rw-r--r--usr.sbin/faithd/prefix.c360
-rw-r--r--usr.sbin/faithd/prefix.h52
-rw-r--r--usr.sbin/faithd/rsh.c8
6 files changed, 610 insertions, 42 deletions
diff --git a/usr.sbin/faithd/Makefile b/usr.sbin/faithd/Makefile
index da285983e0f..b36a0d2fc26 100644
--- a/usr.sbin/faithd/Makefile
+++ b/usr.sbin/faithd/Makefile
@@ -1,7 +1,7 @@
-# $OpenBSD: Makefile,v 1.1 1999/12/20 16:32:53 itojun Exp $
+# $OpenBSD: Makefile,v 1.2 2001/02/15 17:37:33 itojun Exp $
PROG= faithd
-SRCS= faithd.c tcp.c ftp.c rsh.c
+SRCS= faithd.c tcp.c ftp.c rsh.c prefix.c
MAN= faithd.8
diff --git a/usr.sbin/faithd/faithd.8 b/usr.sbin/faithd/faithd.8
index 79b929c0bdc..017733ed062 100644
--- a/usr.sbin/faithd/faithd.8
+++ b/usr.sbin/faithd/faithd.8
@@ -1,5 +1,5 @@
-.\" $OpenBSD: faithd.8,v 1.9 2001/02/15 16:35:16 todd Exp $
-.\" $KAME: faithd.8,v 1.14 2000/09/12 05:20:35 itojun Exp $
+.\" $OpenBSD: faithd.8,v 1.10 2001/02/15 17:37:33 itojun Exp $
+.\" $KAME: faithd.8,v 1.20 2001/01/22 02:23:40 itojun Exp $
.\"
.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
.\" All rights reserved.
@@ -37,6 +37,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl dp
+.Op Fl f Ar configfile
.Ar service
.Op Ar serverpath Op Ar serverargs
.Nm ""
@@ -97,6 +98,24 @@ address prefix, by using
and
.Xr sysctl 8
commands.
+.Pp
+.Nm
+needs a special name-to-address translation logic, so that
+hostnames gets resolved into special
+.Tn IPv6
+address prefix.
+For small-scale installation, use
+.Xr hosts 5 .
+For large-scale installation, it is useful to have
+a DNS server with special address translation support.
+An implementation called
+.Nm totd
+is available
+at
+.Pa http://www.vermicelli.pasta.cs.uit.no/ipv6/software.html .
+Make sure you do not propagate translated DNS records to normal DNS cloud,
+it is highly harmful.
+.Pp
.\".Ss Daemon mode
When
.Nm
@@ -138,22 +157,23 @@ You can also specify
.Ar serverargs
for the arguments for the local daemon.
.Pp
-If
-.Fl d
-is given, debugging information will be generated using
+The following options are available:
+.Bl -tag -width indent
+.It Fl d
+Debugging information will be generated using
.Xr syslog 3 .
-If
-.Fl p
-is given,
-.Nm
-will use privileged TCP port number as source port,
+.It Fl f Ar configfile
+Specify a configuration file for access control.
+See below.
+.It Fl p
+Use privileged TCP port number as source port,
for IPv4 TCP connection toward final destination.
For relaying
.Xr ftp 1
and
.Xr rlogin 1 ,
-.Fl p
-is not necessary as special program code is supplied.
+this flag is not necessary as special program code is supplied.
+.El
.Pp
.Nm
will relay both normal and out-of-band TCP data.
@@ -182,6 +202,52 @@ Inactive sessions will be disconnected in 30 minutes,
to avoid stale sessions from chewing up resources.
This may be inappropriate for some of the services
.Pq should this be configurable? .
+.Ss Access control
+To prevent malicious accesses,
+.Nm
+implements a simple address-based access control.
+With
+.Pa /etc/faithd.conf
+.Po
+or
+.Ar configfile
+specified by
+.Fl f
+.Pc ,
+.Nm
+will avoid relaying unwanted traffic.
+The
+.Pa faithd.conf
+contains directives with the following format:
+.Bl -bullet
+.It
+.Xo
+.Ic Ar src/slen Li deny Ar dst/dlen
+.Xc
+.Pp
+If the source address of a query matches
+.Ar src/slen ,
+and the translated destination address matches
+.Ar dst/dlen ,
+deny the connection.
+.It
+.Xo
+.Ic Ar src/slen Li permit Ar dst/dlen
+.Xc
+.Pp
+If the source address of a query matches
+.Ar src/slen ,
+and the translated destination address matches
+.Ar dst/dlen ,
+permit the connection.
+.El
+.Pp
+The directives are evaluated in sequence,
+and the first matching entry will be effective.
+.\".Pp
+.\"With inetd mode,
+.\"traffic may be filtered by using access control functionality in
+.\".Xr inetd 8 .
.Sh EXAMPLES
Before invoking
.Nm Ns ,
@@ -195,6 +261,7 @@ interface has to be configured properly.
# route add -inet6 3ffe:501:4819:ffff:: -prefixlen 96 ::1
# route change -inet6 3ffe:501:4819:ffff:: -prefixlen 96 -ifp faith0
.Ed
+.Pp
.\".Ss Daemon mode samples
To translate
.Li telnet
@@ -217,7 +284,7 @@ use the following command line:
.Pp
If you would like to pass extra arguments to the local daemon:
.Bd -literal -offset
-# faithd ftpd /usr/libexec/ftpd ftpd -l
+# faithd ftp /usr/libexec/ftpd ftpd -l
.Ed
.Pp
Here are some other examples.
@@ -231,9 +298,24 @@ to translate rsh/rlogin services.
.Ed
.Pp
However, you should be careful when translating rlogin or rsh
-connections. See
+connections.
+See
.Sx SECURITY NOTICE
for more details.
+.Ss Access control samples
+The following illustrates a simple
+.Pa faithd.conf
+setting.
+.Bd -literal -offset
+# permit anyone from 3ffe:501:ffff::/48 to use the translator,
+# to connect to the following IPv4 destinations:
+# - any location except 10.0.0.0/8 and 127.0.0.0/8.
+# Permit no other connections.
+#
+3ffe:501:ffff::/48 deny 10.0.0.0/8
+3ffe:501:ffff::/48 deny 127.0.0.0/8
+3ffe:501:ffff::/48 permit 0.0.0.0/0
+.Ed
.Sh RETURN VALUES
.Nm
exits with
@@ -262,10 +344,14 @@ and other IP-address based authentication, for connections relayed by
.Nm
.Pq and any other TCP relaying services .
.Pp
+Administrators are advised to limit accesses to
+.Nm
+using
+.Pa faithd.conf ,
+or by using IPv6 packet filters.
+It is to protect
.Nm
-itself does not implement access controls, as
-it intends to implement transparent TCP relay services.
-Administrators are advised to filter packets based on IPv6 address.
+service from malicious parties and avoid theft of service/bandwidth.
IPv6 destination address can be limited by
carefully configuring routing entries that points to
.Xr faith 4 ,
diff --git a/usr.sbin/faithd/faithd.c b/usr.sbin/faithd/faithd.c
index bab7391eaae..223bc3ef408 100644
--- a/usr.sbin/faithd/faithd.c
+++ b/usr.sbin/faithd/faithd.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: faithd.c,v 1.9 2000/10/06 02:46:58 itojun Exp $ */
-/* $KAME: faithd.c,v 1.31 2000/10/05 22:20:37 itojun Exp $ */
+/* $OpenBSD: faithd.c,v 1.10 2001/02/15 17:37:33 itojun Exp $ */
+/* $KAME: faithd.c,v 1.35 2001/02/10 05:24:52 itojun Exp $ */
/*
* Copyright (C) 1997 and 1998 WIDE Project.
@@ -85,6 +85,7 @@
#endif
#include "faithd.h"
+#include "prefix.h"
char *serverpath = NULL;
char *serverarg[MAXARGV + 1];
@@ -103,6 +104,7 @@ static int sockfd = 0;
int dflag = 0;
static int pflag = 0;
static int inetd = 0;
+static char *configfile = NULL;
int main __P((int, char **));
#if 0
@@ -167,6 +169,11 @@ inetd_main(int argc, char **argv)
const int on = 1;
char sbuf[NI_MAXSERV], snum[NI_MAXSERV];
+ if (config_load(configfile) < 0 && configfile) {
+ exit_failure("could not load config file");
+ /*NOTREACHED*/
+ }
+
if (strrchr(argv[0], '/') == NULL)
snprintf(path, sizeof(path), "%s/%s", DEFAULT_DIR, argv[0]);
else
@@ -183,11 +190,15 @@ inetd_main(int argc, char **argv)
#endif
melen = sizeof(me);
- if (getsockname(STDIN_FILENO, (struct sockaddr *)&me, &melen) < 0)
+ if (getsockname(STDIN_FILENO, (struct sockaddr *)&me, &melen) < 0) {
exit_failure("getsockname: %s", ERRSTR);
+ /*NOTREACHED*/
+ }
fromlen = sizeof(from);
- if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0)
+ if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, &fromlen) < 0) {
exit_failure("getpeername: %s", ERRSTR);
+ /*NOTREACHED*/
+ }
if (getnameinfo((struct sockaddr *)&me, melen, NULL, 0,
sbuf, sizeof(sbuf), NI_NUMERICHOST) == 0)
service = sbuf;
@@ -201,8 +212,10 @@ inetd_main(int argc, char **argv)
snprintf(procname, sizeof(procname), "accepting port %s", snum);
openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
- if (argc >= MAXARGV)
+ if (argc >= MAXARGV) {
exit_failure("too many arguments");
+ /*NOTREACHED*/
+ }
serverarg[0] = serverpath = path;
for (i = 1; i < argc; i++)
serverarg[i] = argv[i];
@@ -210,8 +223,10 @@ inetd_main(int argc, char **argv)
error = setsockopt(STDIN_FILENO, SOL_SOCKET, SO_OOBINLINE, &on,
sizeof(on));
- if (error < 0)
+ if (error < 0) {
exit_failure("setsockopt(SO_OOBINLINE): %s", ERRSTR);
+ /*NOTREACHED*/
+ }
play_child(STDIN_FILENO, (struct sockaddr *)&from);
exit_failure("should not reach here");
@@ -230,11 +245,14 @@ daemon_main(int argc, char **argv)
char *ns;
#endif /* FAITH_NS */
- while ((c = getopt(argc, argv, "dp46")) != -1) {
+ while ((c = getopt(argc, argv, "df:p46")) != -1) {
switch (c) {
case 'd':
dflag++;
break;
+ case 'f':
+ configfile = optarg;
+ break;
case 'p':
pflag++;
break;
@@ -254,6 +272,11 @@ daemon_main(int argc, char **argv)
argc -= optind;
argv += optind;
+ if (config_load(configfile) < 0 && configfile) {
+ exit_failure("could not load config file");
+ /*NOTREACHED*/
+ }
+
#ifdef FAITH_NS
if ((ns = getenv(FAITH_NS)) != NULL) {
struct sockaddr_storage ss;
@@ -416,8 +439,10 @@ again:
len = sizeof(srcaddr);
s_src = accept(s_wld, (struct sockaddr *)&srcaddr,
&len);
- if (s_src == -1)
+ if (s_src == -1) {
exit_failure("socket: %s", ERRSTR);
+ /*NOTREACHED*/
+ }
child_pid = fork();
@@ -428,6 +453,7 @@ again:
openlog(logname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
play_child(s_src, (struct sockaddr *)&srcaddr);
exit_failure("should never reach here");
+ /*NOTREACHED*/
} else {
/* parent process */
close(s_src);
@@ -450,6 +476,7 @@ play_child(int s_src, struct sockaddr *srcaddr)
int s_dst, error, hport, nresvport, on = 1;
struct timeval tv;
struct sockaddr *sa4;
+ const struct config *conf;
tv.tv_sec = 1;
tv.tv_usec = 0;
@@ -459,8 +486,10 @@ play_child(int s_src, struct sockaddr *srcaddr)
syslog(LOG_INFO, "accepted a client from %s", src);
error = getsockname(s_src, (struct sockaddr *)&dstaddr6, &len);
- if (error == -1)
+ if (error == -1) {
exit_failure("getsockname: %s", ERRSTR);
+ /*NOTREACHED*/
+ }
getnameinfo((struct sockaddr *)&dstaddr6, len,
dst6, sizeof(dst6), NULL, 0, NI_NUMERICHOST);
@@ -497,6 +526,7 @@ play_child(int s_src, struct sockaddr *srcaddr)
(struct sockaddr_in *)&dstaddr4)) {
close(s_src);
exit_failure("map6to4 failed");
+ /*NOTREACHED*/
}
syslog(LOG_INFO, "translating from v6 to v4");
break;
@@ -506,6 +536,7 @@ play_child(int s_src, struct sockaddr *srcaddr)
(struct sockaddr_in6 *)&dstaddr4)) {
close(s_src);
exit_failure("map4to6 failed");
+ /*NOTREACHED*/
}
syslog(LOG_INFO, "translating from v4 to v6");
break;
@@ -519,6 +550,15 @@ play_child(int s_src, struct sockaddr *srcaddr)
sa4 = (struct sockaddr *)&dstaddr4;
getnameinfo(sa4, sa4->sa_len,
dst4, sizeof(dst4), NULL, 0, NI_NUMERICHOST);
+
+ conf = config_match(srcaddr, sa4);
+ if (!conf || !conf->permit) {
+ close(s_src);
+ exit_failure("translation to %s not permitted for %s", dst4,
+ prefix_string(&conf->match));
+ /*NOTREACHED*/
+ }
+
syslog(LOG_INFO, "the translator is connecting to %s", dst4);
setproctitle("port %s, %s -> %s", service, src, dst4);
@@ -540,31 +580,55 @@ play_child(int s_src, struct sockaddr *srcaddr)
s_dst = socket(sa4->sa_family, SOCK_STREAM, 0);
break;
}
- if (s_dst == -1)
+ if (s_dst < 0) {
exit_failure("socket: %s", ERRSTR);
+ /*NOTREACHED*/
+ }
+
+ if (conf->src.a.ss_family) {
+ if (bind(s_dst, (struct sockaddr *)&conf->src.a,
+ conf->src.a.ss_len) < 0) {
+ exit_failure("bind: %s", ERRSTR);
+ /*NOTREACHED*/
+ }
+ }
error = setsockopt(s_dst, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on));
- if (error == -1)
+ if (error < 0) {
exit_failure("setsockopt(SO_OOBINLINE): %s", ERRSTR);
+ /*NOTREACHED*/
+ }
error = setsockopt(s_src, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
- if (error == -1)
+ if (error < 0) {
exit_failure("setsockopt(SO_SNDTIMEO): %s", ERRSTR);
+ /*NOTREACHED*/
+ }
error = setsockopt(s_dst, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
- if (error == -1)
+ if (error < 0) {
exit_failure("setsockopt(SO_SNDTIMEO): %s", ERRSTR);
+ /*NOTREACHED*/
+ }
error = connect(s_dst, sa4, sa4->sa_len);
- if (error == -1)
+ if (error < 0) {
exit_failure("connect: %s", ERRSTR);
+ /*NOTREACHED*/
+ }
switch (hport) {
case FTP_PORT:
ftp_relay(s_src, s_dst);
break;
case RSH_PORT:
+ syslog(LOG_WARNING,
+ "WARINNG: it is insecure to relay rsh port");
rsh_relay(s_src, s_dst);
break;
+ case RLOGIN_PORT:
+ syslog(LOG_WARNING,
+ "WARINNG: it is insecure to relay rlogin port");
+ /*FALLTHROUGH*/
default:
tcp_relay(s_src, s_dst, service);
break;
@@ -590,8 +654,10 @@ faith_prefix(struct sockaddr *dst)
mib[2] = IPPROTO_IPV6;
mib[3] = IPV6CTL_FAITH_PREFIX;
size = sizeof(struct in6_addr);
- if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0)
+ if (sysctl(mib, 4, &faith_prefix, &size, NULL, 0) < 0) {
exit_failure("sysctl: %s", ERRSTR);
+ /*NOTREACHED*/
+ }
if (memcmp(dst, &faith_prefix,
sizeof(struct in6_addr) - sizeof(struct in_addr) == 0) {
@@ -721,11 +787,15 @@ start_daemon(void)
if (daemon(0, 0) == -1)
exit_stderr("daemon: %s", ERRSTR);
- if (signal(SIGCHLD, sig_child) == SIG_ERR)
+ if (signal(SIGCHLD, sig_child) == SIG_ERR) {
exit_failure("signal CHLD: %s", ERRSTR);
+ /*NOTREACHED*/
+ }
- if (signal(SIGTERM, sig_terminate) == SIG_ERR)
+ if (signal(SIGTERM, sig_terminate) == SIG_ERR) {
exit_failure("signal TERM: %s", ERRSTR);
+ /*NOTREACHED*/
+ }
}
static void
@@ -737,7 +807,7 @@ exit_stderr(const char *fmt, ...)
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
- fprintf(stderr, "%s", buf);
+ fprintf(stderr, "%s\n", buf);
exit(EXIT_FAILURE);
}
@@ -986,7 +1056,7 @@ update_myaddrs()
static void
usage()
{
- fprintf(stderr, "usage: %s [-dp] service [serverpath [serverargs]]\n",
+ fprintf(stderr, "usage: %s [-dp] [-f conf] service [serverpath [serverargs]]\n",
faithdname);
exit(0);
}
diff --git a/usr.sbin/faithd/prefix.c b/usr.sbin/faithd/prefix.c
new file mode 100644
index 00000000000..4c124f54845
--- /dev/null
+++ b/usr.sbin/faithd/prefix.c
@@ -0,0 +1,360 @@
+/* $OpenBSD: prefix.c,v 1.1 2001/02/15 17:37:33 itojun Exp $ */
+/* $KAME: prefix.c,v 1.8 2000/11/24 06:16:56 itojun Exp $ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#ifndef offsetof
+#define offsetof(type, member) ((size_t)(u_long)(&((type *)0)->member))
+#endif
+
+#include "faithd.h"
+#include "prefix.h"
+
+static int prefix_set __P((const char *, struct prefix *, int));
+static struct config *config_load1 __P((const char *));
+#if 0
+static void config_show1 __P((const struct config *));
+static void config_show __P((void));
+#endif
+
+struct config *config_list = NULL;
+#ifdef NI_WITHSCOPEID
+const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
+#else
+const int niflags = NI_NUMERICHOST;
+#endif
+
+static int
+prefix_set(s, prefix, slash)
+ const char *s;
+ struct prefix *prefix;
+ int slash;
+{
+ char *p, *q, *r;
+ struct addrinfo hints, *res = NULL;
+ int max;
+ char *a;
+
+ p = strdup(s);
+ q = strchr(p, '/');
+ if (q) {
+ if (!slash)
+ goto fail;
+ *q++ = '\0';
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+ if (getaddrinfo(p, "0", &hints, &res))
+ goto fail;
+ if (res->ai_next || res->ai_addrlen > sizeof(prefix->a))
+ goto fail;
+ memcpy(&prefix->a, res->ai_addr, res->ai_addrlen);
+
+ switch (prefix->a.ss_family) {
+ case AF_INET:
+ max = 32;
+ a = (char *)&((struct sockaddr_in *)&prefix->a)->sin_addr;
+ break;
+ case AF_INET6:
+ max = 128;
+ a = (char *)&((struct sockaddr_in6 *)&prefix->a)->sin6_addr;
+ break;
+ default:
+ a = NULL;
+ max = -1;
+ break;
+ }
+
+ if (q) {
+ r = NULL;
+ prefix->l = (int)strtoul(q, &r, 10);
+ if (!*q || *r)
+ goto fail;
+ if (prefix->l < 0 || prefix->l > max)
+ goto fail;
+ } else
+ prefix->l = max;
+
+ if (p)
+ free(p);
+ if (res)
+ freeaddrinfo(res);
+ return 0;
+
+fail:
+ if (p)
+ free(p);
+ if (res)
+ freeaddrinfo(res);
+ return -1;
+}
+
+const char *
+prefix_string(prefix)
+ const struct prefix *prefix;
+{
+ static char buf[NI_MAXHOST + 20];
+ char hbuf[NI_MAXHOST];
+
+ if (getnameinfo((struct sockaddr *)&prefix->a, prefix->a.ss_len, hbuf,
+ sizeof(hbuf), NULL, 0, niflags))
+ return NULL;
+ snprintf(buf, sizeof(buf), "%s/%d", hbuf, prefix->l);
+ return buf;
+}
+
+int
+prefix_match(prefix, sa)
+ const struct prefix *prefix;
+ const struct sockaddr *sa;
+{
+ struct sockaddr_storage a, b;
+ char *pa, *pb;
+ int off, l;
+
+ if (prefix->a.ss_family != sa->sa_family ||
+ prefix->a.ss_len != sa->sa_len)
+ return 0;
+
+ if (prefix->a.ss_len > sizeof(a) || sa->sa_len > sizeof(b))
+ return 0;
+
+ switch (prefix->a.ss_family) {
+ case AF_INET:
+ off = offsetof(struct sockaddr_in, sin_addr);
+ break;
+ case AF_INET6:
+ off = offsetof(struct sockaddr_in6, sin6_addr);
+ break;
+ default:
+ if (memcmp(&prefix->a, sa, prefix->a.ss_len) != 0)
+ return 0;
+ else
+ return 1;
+ }
+
+ memcpy(&a, &prefix->a, prefix->a.ss_len);
+ memcpy(&b, sa, sa->sa_len);
+ l = prefix->l / 8 + (prefix->l % 8 ? 1 : 0);
+
+ /* overrun check */
+ if (off + l > a.ss_len)
+ return 0;
+
+ pa = ((char *)&a) + off;
+ pb = ((char *)&b) + off;
+ if (prefix->l % 8) {
+ pa[prefix->l / 8] &= 0xff00 >> (prefix->l % 8);
+ pb[prefix->l / 8] &= 0xff00 >> (prefix->l % 8);
+ }
+ if (memcmp(pa, pb, l) != 0)
+ return 0;
+ else
+ return 1;
+}
+
+/*
+ * prefix/prefixlen permit/deny prefix/prefixlen [srcaddr]
+ * 3ffe::/16 permit 10.0.0.0/8 10.1.1.1
+ */
+static struct config *
+config_load1(line)
+ const char *line;
+{
+ struct config *conf;
+ char buf[BUFSIZ];
+ char *p;
+ char *token[4];
+ int i;
+
+ if (strlen(line) + 1 > sizeof(buf))
+ return NULL;
+ strlcpy(buf, line, sizeof(buf));
+
+ p = strchr(buf, '\n');
+ if (!p)
+ return NULL;
+ *p = '\0';
+ p = strchr(buf, '#');
+ if (p)
+ *p = '\0';
+ if (strlen(buf) == 0)
+ return NULL;
+
+ p = buf;
+ memset(token, 0, sizeof(token));
+ for (i = 0; i < sizeof(token) / sizeof(token[0]); i++) {
+ token[i] = strtok(p, "\t ");
+ p = NULL;
+ if (token[i] == NULL)
+ break;
+ }
+ /* extra tokens? */
+ if (strtok(p, "\t ") != NULL)
+ return NULL;
+ /* insufficient tokens */
+ switch (i) {
+ case 3:
+ case 4:
+ break;
+ default:
+ return NULL;
+ }
+
+ conf = (struct config *)malloc(sizeof(*conf));
+ if (conf == NULL)
+ return NULL;
+ memset(conf, 0, sizeof(*conf));
+
+ if (strcasecmp(token[1], "permit") == 0)
+ conf->permit = 1;
+ else if (strcasecmp(token[1], "deny") == 0)
+ conf->permit = 0;
+ else {
+ /* invalid keyword is considered as "deny" */
+ conf->permit = 0;
+ }
+
+ if (prefix_set(token[0], &conf->match, 1) < 0)
+ goto fail;
+ if (prefix_set(token[2], &conf->dest, 1) < 0)
+ goto fail;
+ if (token[3]) {
+ if (prefix_set(token[3], &conf->src, 0) < 0)
+ goto fail;
+ }
+
+ return conf;
+
+fail:
+ free(conf);
+ return NULL;
+}
+
+int
+config_load(configfile)
+ const char *configfile;
+{
+ FILE *fp;
+ char buf[BUFSIZ];
+ struct config *conf, *p;
+ struct config sentinel;
+
+ config_list = NULL;
+
+ if (!configfile)
+ configfile = _PATH_PREFIX_CONF;
+ fp = fopen(configfile, "r");
+ if (fp == NULL)
+ return -1;
+
+ p = &sentinel;
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ conf = config_load1(buf);
+ if (conf) {
+ p->next = conf;
+ p = p->next;
+ }
+ }
+ config_list = sentinel.next;
+
+ fclose(fp);
+ return 0;
+}
+
+#if 0
+static void
+config_show1(conf)
+ const struct config *conf;
+{
+ const char *p;
+
+ p = prefix_string(&conf->match);
+ printf("%s", p ? p : "?");
+
+ if (conf->permit)
+ printf(" permit");
+ else
+ printf(" deny");
+
+ p = prefix_string(&conf->dest);
+ printf(" %s", p ? p : "?");
+
+ printf("\n");
+}
+
+static void
+config_show()
+{
+ struct config *conf;
+
+ for (conf = config_list; conf; conf = conf->next)
+ config_show1(conf);
+}
+#endif
+
+const struct config *
+config_match(sa1, sa2)
+ struct sockaddr *sa1, *sa2;
+{
+ static struct config conf;
+ const struct config *p;
+
+ if (sa1->sa_len > sizeof(conf.match.a) ||
+ sa2->sa_len > sizeof(conf.dest.a))
+ return NULL;
+
+ memset(&conf, 0, sizeof(conf));
+ if (!config_list) {
+ conf.permit = 1;
+ memcpy(&conf.match.a, sa1, sa1->sa_len);
+ memcpy(&conf.dest.a, sa2, sa2->sa_len);
+ return &conf;
+ }
+
+ for (p = config_list; p; p = p->next)
+ if (prefix_match(&p->match, sa1) && prefix_match(&p->dest, sa2))
+ return p;
+
+ return NULL;
+}
diff --git a/usr.sbin/faithd/prefix.h b/usr.sbin/faithd/prefix.h
new file mode 100644
index 00000000000..971a4347f9a
--- /dev/null
+++ b/usr.sbin/faithd/prefix.h
@@ -0,0 +1,52 @@
+/* $OpenBSD: prefix.h,v 1.1 2001/02/15 17:37:33 itojun Exp $ */
+/* $KAME: prefix.h,v 1.3 2000/11/19 11:45:38 itojun Exp $ */
+
+/*
+ * Copyright (C) 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.
+ */
+
+struct prefix {
+ struct sockaddr_storage a;
+ int l;
+};
+
+struct config {
+ struct config *next;
+
+ int permit;
+ struct prefix match;
+ struct prefix dest;
+ struct prefix src; /* src to use for outgoing connection */
+};
+
+#define _PATH_PREFIX_CONF "/etc/faithd.conf"
+
+extern const char *prefix_string __P((const struct prefix *));
+extern int prefix_match __P((const struct prefix *, const struct sockaddr *));
+extern int config_load __P((const char *));
+extern const struct config *config_match __P((struct sockaddr *, struct sockaddr *));
diff --git a/usr.sbin/faithd/rsh.c b/usr.sbin/faithd/rsh.c
index 3603e2d5577..d7cdc1282e2 100644
--- a/usr.sbin/faithd/rsh.c
+++ b/usr.sbin/faithd/rsh.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: rsh.c,v 1.3 2000/05/31 03:09:22 itojun Exp $ */
-/* $KAME: rsh.c,v 1.3 2000/05/31 03:06:07 itojun Exp $ */
+/* $OpenBSD: rsh.c,v 1.4 2001/02/15 17:37:33 itojun Exp $ */
+/* $KAME: rsh.c,v 1.5 2001/02/15 17:28:04 itojun Exp $ */
/*
* Copyright (C) 1997 and 1998 WIDE Project.
@@ -70,7 +70,7 @@ rsh_relay(int s_src, int s_dst)
if (error == -1)
exit_failure("select %d: %s", s_src, ERRSTR);
else if (error == 0)
- exit_failure("connecion timeout");
+ exit_failure("connection timeout");
n = read(s_src, rshbuf, sizeof(rshbuf));
if (rshbuf[0] != 0) {
@@ -181,7 +181,7 @@ rsh_dual_relay(int s_src, int s_dst)
if (error == -1)
exit_failure("select 4 sockets: %s", ERRSTR);
else if (error == 0)
- exit_failure("connecion timeout");
+ exit_failure("connection timeout");
if (half == NO && FD_ISSET(s_src, &readfds)) {
s_rcv = s_src;