diff options
Diffstat (limited to 'contrib')
79 files changed, 7442 insertions, 42 deletions
diff --git a/contrib/binutils/include/libiberty.h b/contrib/binutils/include/libiberty.h index 4e69734..555f5c7 100644 --- a/contrib/binutils/include/libiberty.h +++ b/contrib/binutils/include/libiberty.h @@ -102,7 +102,7 @@ extern int writeargv PARAMS ((char **, FILE *)); is 1, we found it so don't provide any declaration at all. */ #if !HAVE_DECL_BASENAME #if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__) || defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (__MINGW32__) || defined (HAVE_DECL_BASENAME) -extern char *basename (const char *); +#include <libgen.h> #else /* Do not allow basename to be used if there is no prototype seen. We either need to use the above prototype or have one from diff --git a/contrib/blacklist/Makefile b/contrib/blacklist/Makefile new file mode 100644 index 0000000..da4411d --- /dev/null +++ b/contrib/blacklist/Makefile @@ -0,0 +1,5 @@ +# $NetBSD: Makefile,v 1.2 2015/01/22 17:49:41 christos Exp $ + +SUBDIR = lib .WAIT include bin etc libexec + +.include <bsd.subdir.mk> diff --git a/contrib/blacklist/Makefile.inc b/contrib/blacklist/Makefile.inc new file mode 100644 index 0000000..85c8278 --- /dev/null +++ b/contrib/blacklist/Makefile.inc @@ -0,0 +1,10 @@ +# $NetBSD: Makefile.inc,v 1.3 2015/01/23 03:57:22 christos Exp $ + +WARNS=6 +.if !defined(LIB) +LDADD+= -lblacklist +DPADD+= ${LIBBLACKLIST} +.endif +CPPFLAGS+= -I${.CURDIR}/../include +CPPFLAGS+=-DHAVE_STRUCT_SOCKADDR_SA_LEN -DHAVE_UTIL_H -DHAVE_DB_H + diff --git a/contrib/blacklist/README b/contrib/blacklist/README new file mode 100644 index 0000000..44e1026 --- /dev/null +++ b/contrib/blacklist/README @@ -0,0 +1,103 @@ +# $NetBSD: README,v 1.7 2015/01/26 00:34:50 christos Exp $ + +This package contains library that can be used by network daemons to +communicate with a packet filter via a daemon to enforce opening and +closing ports dynamically based on policy. + +The interface to the packet filter is in libexec/blacklistd-helper +(this is currently designed for npf) and the configuration file +(inspired from inetd.conf) is in etc/blacklistd.conf. + +On NetBSD you can find an example npf.conf and blacklistd.conf in +/usr/share/examples/blacklistd; you need to adjust the interface +in npf.conf and copy both files to /etc; then you just enable +blacklistd=YES in /etc/rc.conf, start it up, and you are all set. + +There is also a startup file in etc/rc.d/blacklistd + +Patches to various daemons to add blacklisting capabilitiers are in the +"diff" directory: + - OpenSSH: diff/ssh.diff [tcp socket example] + - Bind: diff/named.diff [both tcp and udp] + - ftpd: diff/ftpd.diff [tcp] + +These patches have been applied to NetBSD-current. + +The network daemon (for example sshd) communicates to blacklistd, via +a unix socket like syslog. The library calls are simple and everything +is handled by the library. In the simplest form the only thing the +daemon needs to do is to call: + + blacklist(action, acceptedfd, message); + +Where: + action = 0 -> successful login clear blacklist state + 1 -> failed login, add to the failed count + acceptedfd -> the file descriptor where the server is + connected to the remote client. It is used + to determine the listening socket, and the + remote address. This allows any program to + contact the blacklist daemon, since the verification + if the program has access to the listening + socket is done by virtue that the port + number is retrieved from the kernel. + message -> an optional string that is used in debugging logs. + +Unfortunately there is no way to get information about the "peer" +from a udp socket, because there is no connection and that information +is kept with the server. In that case the daemon can provide the +peer information to blacklistd via: + + blacklist_sa(action, acceptedfd, sockaddr, sockaddr_len, message); + +The configuration file contains entries of the form: + +# Blacklist rule +# host/Port type protocol owner name nfail disable +192.168.1.1:ssh stream tcp * -int 10 1m +8.8.8.8:ssh stream tcp * -ext 6 60m +ssh stream tcp6 * * 6 60m +http stream tcp * * 6 60m + +Here note that owner is * because the connection is done from the +child ssh socket which runs with user privs. We treat ipv4 connections +differently by maintaining two different rules one for the external +interface and one from the internal We also register for both tcp +and tcp6 since those are different listening sockets and addresses; +we don't bother with ipv6 and separate rules. We use nfail = 6, +because ssh allows 3 password attempts per connection, and this +will let us have 2 connections before blocking. Finally we block +for an hour; we could block forever too by specifying * in the +duration column. + +blacklistd and the library use syslog(3) to report errors. The +blacklist filter state is persisted automatically in /var/db/blacklistd.db +so that if the daemon is restarted, it remembers what connections +is currently handling. To start from a fresh state (if you restart +npf too for example), you can use -f. To watch the daemon at work, +you can use -d. + +The current control file is designed for npf, and it uses the +dynamic rule feature. You need to create a dynamic rule in your +/etc/npf.conf on the group referring to the interface you want to block +called blacklistd as follows: + +ext_if=bge0 +int_if=sk0 + +group "external" on $ext_if { + ... + ruleset "blacklistd-ext" + ruleset "blacklistd" + ... +} + +group "internal" on $int_if { + ... + ruleset "blacklistd-int" + ... +} + +Enjoy, + +christos diff --git a/contrib/blacklist/TODO b/contrib/blacklist/TODO new file mode 100644 index 0000000..9925020 --- /dev/null +++ b/contrib/blacklist/TODO @@ -0,0 +1,21 @@ +# $NetBSD: TODO,v 1.7 2015/01/23 21:34:01 christos Exp $ + +- don't poll periodically, find the next timeout +- use the socket also for commands? Or separate socket? +- add functionality to the control program. Should it change the database + directly, or talk to the daemon to have it do it? +- perhaps handle interfaces too instead of addresses for dynamic ip? + <bge0/4>? What to do with multiple addresses? +- perhaps rate limit against DoS +- perhaps instead of scanning the list have a sparse map by port? +- do we want to use libnpf directly for efficiency? +- add more daemons ftpd? +- do we care about the db state becoming too large? +- instead of a yes = bump one, no = return to 0 interface, do we want + to have something more flexible like? + +n + -n + block + unblock +- do we need an api in blacklistctl to perform maintenance +- fix the blacklistctl output to be more user friendly diff --git a/contrib/blacklist/bin/Makefile b/contrib/blacklist/bin/Makefile new file mode 100644 index 0000000..280c72f --- /dev/null +++ b/contrib/blacklist/bin/Makefile @@ -0,0 +1,15 @@ +# $NetBSD: Makefile,v 1.11 2015/01/27 19:40:36 christos Exp $ + +BINDIR=/sbin + +PROGS=blacklistd blacklistctl +MAN.blacklistd=blacklistd.8 blacklistd.conf.5 +MAN.blacklistctl=blacklistctl.8 +SRCS.blacklistd = blacklistd.c conf.c run.c state.c support.c internal.c +SRCS.blacklistctl = blacklistctl.c conf.c state.c support.c internal.c +DBG=-g + +LDADD+=-lutil +DPADD+=${LIBUTIL} + +.include <bsd.prog.mk> diff --git a/contrib/blacklist/bin/blacklistctl.8 b/contrib/blacklist/bin/blacklistctl.8 new file mode 100644 index 0000000..d8ed1f0 --- /dev/null +++ b/contrib/blacklist/bin/blacklistctl.8 @@ -0,0 +1,81 @@ +.\" $NetBSD: blacklistctl.8,v 1.7 2015/04/30 06:20:43 riz Exp $ +.\" +.\" Copyright (c) 2015 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Christos Zoulas. +.\" +.\" 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd April 29, 2015 +.Dt BLACKLISTCTL 8 +.Os +.Sh NAME +.Nm blacklistctl +.Nd display and change the state of blacklistd +.Sh SYNOPSIS +.Nm +.Cm dump +.Op Fl abdnrw +.Sh DESCRIPTION +.Nm +is a program used to display the state of +.Xr blacklistd 8 +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl a +Show all database entries, by default it shows only the embryonic ones. +.It Fl b +Show only the blocked entries. +.It Fl d +Increase debugging level. +.It Fl n +Don't display a header. +.It Fl r +Show the remaining blocked time instead of the last activity time. +.It Fl w +Normally the width of addresses is good for IPv4, the +.Fl w +flag, makes the display wide enough for IPv6 addresses. +.El +.Sh SEE ALSO +.Xr blacklistd 8 +.Sh NOTES +Sometimes the reported number of failed attempts can exceed the number +of attempts that +.Xr blacklistd 8 +is configured to block. +This can happen either because the rule has been removed manually, or +because there were more attempts in flight while the rule block was being +added. +This condition is normal; in that case +.Xr blacklistd 8 +will first attempt to remove the existing rule, and then it will re-add +it to make sure that there is only one rule active. +.Sh HISTORY +.Nm +appeared in +.Nx 7 . +.Sh AUTHORS +.An Christos Zoulas diff --git a/contrib/blacklist/bin/blacklistctl.c b/contrib/blacklist/bin/blacklistctl.c new file mode 100644 index 0000000..d202fb1 --- /dev/null +++ b/contrib/blacklist/bin/blacklistctl.c @@ -0,0 +1,151 @@ +/* $NetBSD: blacklistctl.c,v 1.20 2016/04/04 15:52:56 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: blacklistctl.c,v 1.20 2016/04/04 15:52:56 christos Exp $"); + +#include <stdio.h> +#include <time.h> +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif +#ifdef HAVE_UTIL_H +#include <util.h> +#endif +#include <fcntl.h> +#include <string.h> +#include <syslog.h> +#include <err.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/socket.h> + +#include "conf.h" +#include "state.h" +#include "internal.h" +#include "support.h" + +static __dead void +usage(int c) +{ + if (c == 0) + warnx("Missing/unknown command"); + else + warnx("Unknown option `%c'", (char)c); + fprintf(stderr, "Usage: %s dump [-abdnrw]\n", getprogname()); + exit(EXIT_FAILURE); +} + +int +main(int argc, char *argv[]) +{ + const char *dbname = _PATH_BLSTATE; + DB *db; + struct conf c; + struct dbinfo dbi; + unsigned int i; + struct timespec ts; + int all, blocked, remain, wide, noheader; + int o; + + noheader = wide = blocked = all = remain = 0; + lfun = dlog; + + if (argc == 1 || strcmp(argv[1], "dump") != 0) + usage(0); + + argc--; + argv++; + + while ((o = getopt(argc, argv, "abD:dnrw")) != -1) + switch (o) { + case 'a': + all = 1; + blocked = 0; + break; + case 'b': + blocked = 1; + case 'D': + dbname = optarg; + break; + break; + case 'd': + debug++; + break; + case 'n': + noheader = 1; + break; + case 'r': + remain = 1; + break; + case 'w': + wide = 1; + break; + default: + usage(o); + break; + } + + db = state_open(dbname, O_RDONLY, 0); + if (db == NULL) + err(EXIT_FAILURE, "Can't open `%s'", dbname); + + clock_gettime(CLOCK_REALTIME, &ts); + wide = wide ? 8 * 4 + 7 : 4 * 3 + 3; + if (!noheader) + printf("%*.*s/ma:port\tid\tnfail\t%s\n", wide, wide, + "address", remain ? "remaining time" : "last access"); + for (i = 1; state_iterate(db, &c, &dbi, i) != 0; i = 0) { + char buf[BUFSIZ]; + if (!all) { + if (blocked) { + if (dbi.count < c.c_nfail) + continue; + } else { + if (dbi.count >= c.c_nfail) + continue; + } + } + sockaddr_snprintf(buf, sizeof(buf), "%a", (void *)&c.c_ss); + printf("%*.*s/%d:%d\t", wide, wide, buf, c.c_lmask, c.c_port); + if (remain) + fmtydhms(buf, sizeof(buf), + c.c_duration - (ts.tv_sec - dbi.last)); + else + fmttime(buf, sizeof(buf), dbi.last); + printf("%s\t%d/%d\t%-s\n", dbi.id, dbi.count, c.c_nfail, buf); + } + state_close(db); + return EXIT_SUCCESS; +} diff --git a/contrib/blacklist/bin/blacklistd.8 b/contrib/blacklist/bin/blacklistd.8 new file mode 100644 index 0000000..80a53da --- /dev/null +++ b/contrib/blacklist/bin/blacklistd.8 @@ -0,0 +1,222 @@ +.\" $NetBSD: blacklistd.8,v 1.15 2016/03/11 17:16:40 christos Exp $ +.\" +.\" Copyright (c) 2015 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Christos Zoulas. +.\" +.\" 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd June 4, 2015 +.Dt BLACKLISTD 8 +.Os +.Sh NAME +.Nm blacklistd +.Nd block and release ports on demand to avoid DoS abuse +.Sh SYNOPSIS +.Nm +.Op Fl dfrv +.Op Fl C Ar controlprog +.Op Fl c Ar configfile +.Op Fl D Ar dbfile +.Op Fl P Ar sockpathsfile +.Op Fl R Ar rulename +.Op Fl s Ar sockpath +.Op Fl t Ar timeout +.Sh DESCRIPTION +.Nm +is a daemon similar to +.Xr syslogd 8 +that listens to a sockets at paths specified in the +.Ar sockpathsfile +for notifications from other daemons about successful or failed connection +attempts. +If no such file is specified, then it only listens to the socket path +specified by +.Ar sockspath +or if that is not specified to +.Pa /var/run/blacklistd.sock . +Each notification contains an (action, port, protocol, address, owner) tuple +that identifies the remote connection and the action. +This tuple is consulted against entries in +.Ar configfile +with syntax specified in +.Xr blacklistd.conf 5 . +If an entry is matched, a state entry is created for that tuple. +Each entry contains a number of tries limit and a duration. +.Pp +If the action is +.Dq add +and the number of tries limit is reached, then a +control script +.Ar controlprog +is invoked with arguments: +.Bd -literal -offset indent +control add <rulename> <proto> <address> <mask> <port> +.Ed +.Pp +and should invoke a packet filter command to block the connection +specified by the arguments. +The +.Ar rulename +argument can be set from the command line (default +.Dv blacklistd ) . +The script could print a numerical id to stdout as a handle for +the rule that can be used later to remove that connection, but +that is not required as all information to remove the rule is +kept. +.Pp +If the action is +.Dq remove +Then the same control script is invoked as: +.Bd -literal -offset indent +control remove <rulename> <proto> <address> <mask> <port> <id> +.Ed +.Pp +where +.Ar id +is the number returned from the +.Dq add +action. +.Pp +.Nm +maintains a database of known connections in +.Ar dbfile . +On startup it reads entries from that file, and updates its internal state. +.Pp +.Nm +checks the list of active entries every +.Ar timeout +seconds (default +.Dv 15 ) +and removes entries and block rules using the control program as necessary. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl C Ar controlprog +Use +.Ar controlprog +to communicate with the packet filter, usually +.Pa /usr/libexec/blacklistd-helper . +The following arguments are passed to the control program: +.Bl -tag -width protocol +.It action +The action to perform: +.Dv add , +.Dv rem , +or +.Dv flush +to add, remove or flush a firewall rule. +.It name +The rule name. +.It protocol +The optional protocol name (can be empty): +.Dv tcp , +.Dv tcp6 , +.Dv udp , +.Dv udp6 . +.It address +The IPv4 or IPv6 numeric address to be blocked or released. +.It mask +The numeric mask to be applied to the blocked or released address +.It port +The optional numeric port to be blocked (can be empty). +.It id +For packet filters that support removal of rules by rule identifier, the +identifier of the rule to be removed. +The add command is expected to return the rule identifier string to stdout. +.El +.It Fl c Ar configuration +The name of the configuration file to read, usually +.Pa /etc/blacklistd.conf . +.It Fl D Ar dbfile +The Berkeley DB file where +.Nm +stores its state, usually +.Pa /var/run/blacklistd.db . +.It Fl d +Normally, +.Nm +disassociates itself from the terminal unless the +.Fl d +flag is specified, in which case it stays in the foreground. +.It Fl f +Truncate the state database and flush all the rules named +.Ar rulename +are deleted by invoking the control script as: +.Bd -literal -offset indent +control flush <rulename> +.Ed +.It Fl P Ar sockspathsfile +A file containing a list of pathnames, one per line that +.Nm +will create sockets to listen to. +This is useful for chrooted environments. +.It Fl R Ar rulename +Specify the default rule name for the packet filter rules, usually +.Dv blacklistd . +.It Fl r +Re-read the firewall rules from the internal database, then +remove and re-add them. +This helps for packet filters that don't retain state across reboots. +.It Fl s Ar sockpath +Add +.Ar sockpath +to the list of Unix sockets +.Nm +listens to. +.It Fl t Ar timeout +The interval in seconds +.Nm +polls the state file to update the rules. +.It Fl v +Cause +.Nm +to print +diagnostic messages to +.Dv stdout +instead of +.Xr syslogd 8 . +.El +.Sh FILES +.Bl -tag -width /usr/libexec/blacklistd-helper -compact +.It Pa /usr/libexec/blacklistd-helper +Shell script invoked to interface with the packet filter. +.It Pa /etc/blacklistd.conf +Configuration file. +.It Pa /var/db/blacklistd.db +Database of current connection entries. +.It Pa /var/run/blacklistd.sock +Socket to receive connection notifications. +.El +.Sh SEE ALSO +.Xr blacklistd.conf 5 , +.Xr blacklistctl 8 , +.Xr npfctl 8 , +.Xr syslogd 8 +.Sh HISTORY +.Nm +appeared in +.Nx 7 . +.Sh AUTHORS +.An Christos Zoulas diff --git a/contrib/blacklist/bin/blacklistd.c b/contrib/blacklist/bin/blacklistd.c new file mode 100644 index 0000000..c16b18e --- /dev/null +++ b/contrib/blacklist/bin/blacklistd.c @@ -0,0 +1,537 @@ +/* $NetBSD: blacklistd.c,v 1.34 2016/04/04 15:52:56 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <sys/cdefs.h> +__RCSID("$NetBSD: blacklistd.c,v 1.34 2016/04/04 15:52:56 christos Exp $"); + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/queue.h> + +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif +#ifdef HAVE_UTIL_H +#include <util.h> +#endif +#include <string.h> +#include <signal.h> +#include <netdb.h> +#include <stdio.h> +#include <stdbool.h> +#include <string.h> +#include <inttypes.h> +#include <syslog.h> +#include <ctype.h> +#include <limits.h> +#include <errno.h> +#include <poll.h> +#include <fcntl.h> +#include <err.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> +#include <ifaddrs.h> +#include <netinet/in.h> + +#include "bl.h" +#include "internal.h" +#include "conf.h" +#include "run.h" +#include "state.h" +#include "support.h" + +static const char *configfile = _PATH_BLCONF; +static DB *state; +static const char *dbfile = _PATH_BLSTATE; +static sig_atomic_t readconf; +static sig_atomic_t done; +static int vflag; + +static void +sigusr1(int n __unused) +{ + debug++; +} + +static void +sigusr2(int n __unused) +{ + debug--; +} + +static void +sighup(int n __unused) +{ + readconf++; +} + +static void +sigdone(int n __unused) +{ + done++; +} + +static __dead void +usage(int c) +{ + if (c) + warnx("Unknown option `%c'", (char)c); + fprintf(stderr, "Usage: %s [-vdfr] [-c <config>] [-R <rulename>] " + "[-P <sockpathsfile>] [-C <controlprog>] [-D <dbfile>] " + "[-s <sockpath>] [-t <timeout>]\n", getprogname()); + exit(EXIT_FAILURE); +} + +static int +getremoteaddress(bl_info_t *bi, struct sockaddr_storage *rss, socklen_t *rsl) +{ + *rsl = sizeof(*rss); + memset(rss, 0, *rsl); + + if (getpeername(bi->bi_fd, (void *)rss, rsl) != -1) + return 0; + + if (errno != ENOTCONN) { + (*lfun)(LOG_ERR, "getpeername failed (%m)"); + return -1; + } + + if (bi->bi_slen == 0) { + (*lfun)(LOG_ERR, "unconnected socket with no peer in message"); + return -1; + } + + switch (bi->bi_ss.ss_family) { + case AF_INET: + *rsl = sizeof(struct sockaddr_in); + break; + case AF_INET6: + *rsl = sizeof(struct sockaddr_in6); + break; + default: + (*lfun)(LOG_ERR, "bad client passed socket family %u", + (unsigned)bi->bi_ss.ss_family); + return -1; + } + + if (*rsl != bi->bi_slen) { + (*lfun)(LOG_ERR, "bad client passed socket length %u != %u", + (unsigned)*rsl, (unsigned)bi->bi_slen); + return -1; + } + + memcpy(rss, &bi->bi_ss, *rsl); + +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + if (*rsl != rss->ss_len) { + (*lfun)(LOG_ERR, + "bad client passed socket internal length %u != %u", + (unsigned)*rsl, (unsigned)rss->ss_len); + return -1; + } +#endif + return 0; +} + +static void +process(bl_t bl) +{ + struct sockaddr_storage rss; + socklen_t rsl; + char rbuf[BUFSIZ]; + bl_info_t *bi; + struct conf c; + struct dbinfo dbi; + struct timespec ts; + + if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { + (*lfun)(LOG_ERR, "clock_gettime failed (%m)"); + return; + } + + if ((bi = bl_recv(bl)) == NULL) { + (*lfun)(LOG_ERR, "no message (%m)"); + return; + } + + if (getremoteaddress(bi, &rss, &rsl) == -1) + goto out; + + if (debug) { + sockaddr_snprintf(rbuf, sizeof(rbuf), "%a:%p", (void *)&rss); + (*lfun)(LOG_DEBUG, "processing type=%d fd=%d remote=%s msg=%s" + " uid=%lu gid=%lu", bi->bi_type, bi->bi_fd, rbuf, + bi->bi_msg, (unsigned long)bi->bi_uid, + (unsigned long)bi->bi_gid); + } + + if (conf_find(bi->bi_fd, bi->bi_uid, &rss, &c) == NULL) { + (*lfun)(LOG_DEBUG, "no rule matched"); + goto out; + } + + + if (state_get(state, &c, &dbi) == -1) + goto out; + + if (debug) { + char b1[128], b2[128]; + (*lfun)(LOG_DEBUG, "%s: db state info for %s: count=%d/%d " + "last=%s now=%s", __func__, rbuf, dbi.count, c.c_nfail, + fmttime(b1, sizeof(b1), dbi.last), + fmttime(b2, sizeof(b2), ts.tv_sec)); + } + + switch (bi->bi_type) { + case BL_ADD: + dbi.count++; + dbi.last = ts.tv_sec; + if (dbi.id[0]) { + /* + * We should not be getting this since the rule + * should have blocked the address. A possible + * explanation is that someone removed that rule, + * and another would be that we got another attempt + * before we added the rule. In anycase, we remove + * and re-add the rule because we don't want to add + * it twice, because then we'd lose track of it. + */ + (*lfun)(LOG_DEBUG, "rule exists %s", dbi.id); + (void)run_change("rem", &c, dbi.id, 0); + dbi.id[0] = '\0'; + } + if (c.c_nfail != -1 && dbi.count >= c.c_nfail) { + int res = run_change("add", &c, dbi.id, sizeof(dbi.id)); + if (res == -1) + goto out; + sockaddr_snprintf(rbuf, sizeof(rbuf), "%a", + (void *)&rss); + (*lfun)(LOG_INFO, + "blocked %s/%d:%d for %d seconds", + rbuf, c.c_lmask, c.c_port, c.c_duration); + + } + break; + case BL_DELETE: + if (dbi.last == 0) + goto out; + dbi.last = 0; + break; + default: + (*lfun)(LOG_ERR, "unknown message %d", bi->bi_type); + } + if (state_put(state, &c, &dbi) == -1) + goto out; +out: + close(bi->bi_fd); +} + +static void +update_interfaces(void) +{ + struct ifaddrs *oifas, *nifas; + + if (getifaddrs(&nifas) == -1) + return; + + oifas = ifas; + ifas = nifas; + + if (oifas) + freeifaddrs(oifas); +} + +static void +update(void) +{ + struct timespec ts; + struct conf c; + struct dbinfo dbi; + unsigned int f, n; + char buf[128]; + void *ss = &c.c_ss; + + if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { + (*lfun)(LOG_ERR, "clock_gettime failed (%m)"); + return; + } + +again: + for (n = 0, f = 1; state_iterate(state, &c, &dbi, f) == 1; + f = 0, n++) + { + time_t when = c.c_duration + dbi.last; + if (debug > 1) { + char b1[64], b2[64]; + sockaddr_snprintf(buf, sizeof(buf), "%a:%p", ss); + (*lfun)(LOG_DEBUG, "%s:[%u] %s count=%d duration=%d " + "last=%s " "now=%s", __func__, n, buf, dbi.count, + c.c_duration, fmttime(b1, sizeof(b1), dbi.last), + fmttime(b2, sizeof(b2), ts.tv_sec)); + } + if (c.c_duration == -1 || when >= ts.tv_sec) + continue; + if (dbi.id[0]) { + run_change("rem", &c, dbi.id, 0); + sockaddr_snprintf(buf, sizeof(buf), "%a", ss); + syslog(LOG_INFO, "released %s/%d:%d after %d seconds", + buf, c.c_lmask, c.c_port, c.c_duration); + } + state_del(state, &c); + goto again; + } +} + +static void +addfd(struct pollfd **pfdp, bl_t **blp, size_t *nfd, size_t *maxfd, + const char *path) +{ + bl_t bl = bl_create(true, path, vflag ? vdlog : vsyslog); + if (bl == NULL || !bl_isconnected(bl)) + exit(EXIT_FAILURE); + if (*nfd >= *maxfd) { + *maxfd += 10; + *blp = realloc(*blp, sizeof(**blp) * *maxfd); + if (*blp == NULL) + err(EXIT_FAILURE, "malloc"); + *pfdp = realloc(*pfdp, sizeof(**pfdp) * *maxfd); + if (*pfdp == NULL) + err(EXIT_FAILURE, "malloc"); + } + + (*pfdp)[*nfd].fd = bl_getfd(bl); + (*pfdp)[*nfd].events = POLLIN; + (*blp)[*nfd] = bl; + *nfd += 1; +} + +static void +uniqueadd(struct conf ***listp, size_t *nlist, size_t *mlist, struct conf *c) +{ + struct conf **list = *listp; + + if (c->c_name[0] == '\0') + return; + for (size_t i = 0; i < *nlist; i++) { + if (strcmp(list[i]->c_name, c->c_name) == 0) + return; + } + if (*nlist == *mlist) { + *mlist += 10; + void *p = realloc(*listp, *mlist * sizeof(*list)); + if (p == NULL) + err(EXIT_FAILURE, "Can't allocate for rule list"); + list = *listp = p; + } + list[(*nlist)++] = c; +} + +static void +rules_flush(void) +{ + struct conf **list; + size_t nlist, mlist; + + list = NULL; + mlist = nlist = 0; + for (size_t i = 0; i < rconf.cs_n; i++) + uniqueadd(&list, &nlist, &mlist, &rconf.cs_c[i]); + for (size_t i = 0; i < lconf.cs_n; i++) + uniqueadd(&list, &nlist, &mlist, &lconf.cs_c[i]); + + for (size_t i = 0; i < nlist; i++) + run_flush(list[i]); + free(list); +} + +static void +rules_restore(void) +{ + struct conf c; + struct dbinfo dbi; + unsigned int f; + + for (f = 1; state_iterate(state, &c, &dbi, f) == 1; f = 0) { + if (dbi.id[0] == '\0') + continue; + (void)run_change("rem", &c, dbi.id, 0); + (void)run_change("add", &c, dbi.id, sizeof(dbi.id)); + } +} + +int +main(int argc, char *argv[]) +{ + int c, tout, flags, flush, restore; + const char *spath, *blsock; + + setprogname(argv[0]); + + spath = NULL; + blsock = _PATH_BLSOCK; + flush = 0; + restore = 0; + tout = 0; + flags = O_RDWR|O_EXCL|O_CLOEXEC; + while ((c = getopt(argc, argv, "C:c:D:dfP:rR:s:t:v")) != -1) { + switch (c) { + case 'C': + controlprog = optarg; + break; + case 'c': + configfile = optarg; + break; + case 'D': + dbfile = optarg; + break; + case 'd': + debug++; + break; + case 'f': + flush++; + break; + case 'P': + spath = optarg; + break; + case 'R': + rulename = optarg; + break; + case 'r': + restore++; + break; + case 's': + blsock = optarg; + break; + case 't': + tout = atoi(optarg) * 1000; + break; + case 'v': + vflag++; + break; + default: + usage(c); + } + } + + argc -= optind; + if (argc) + usage(0); + + signal(SIGHUP, sighup); + signal(SIGINT, sigdone); + signal(SIGQUIT, sigdone); + signal(SIGTERM, sigdone); + signal(SIGUSR1, sigusr1); + signal(SIGUSR2, sigusr2); + + openlog(getprogname(), LOG_PID, LOG_DAEMON); + + if (debug) { + lfun = dlog; + if (tout == 0) + tout = 5000; + } else { + if (tout == 0) + tout = 15000; + } + + update_interfaces(); + conf_parse(configfile); + if (flush) { + rules_flush(); + flags |= O_TRUNC; + } + + if (restore) + rules_restore(); + + struct pollfd *pfd = NULL; + bl_t *bl = NULL; + size_t nfd = 0; + size_t maxfd = 0; + + if (spath == NULL) + addfd(&pfd, &bl, &nfd, &maxfd, blsock); + else { + FILE *fp = fopen(spath, "r"); + char *line; + if (fp == NULL) + err(EXIT_FAILURE, "Can't open `%s'", spath); + for (; (line = fparseln(fp, NULL, NULL, NULL, 0)) != NULL; + free(line)) + addfd(&pfd, &bl, &nfd, &maxfd, line); + fclose(fp); + } + + state = state_open(dbfile, flags, 0600); + if (state == NULL) + state = state_open(dbfile, flags | O_CREAT, 0600); + if (state == NULL) + return EXIT_FAILURE; + + if (!debug) { + if (daemon(0, 0) == -1) + err(EXIT_FAILURE, "daemon failed"); + if (pidfile(NULL) == -1) + err(EXIT_FAILURE, "Can't create pidfile"); + } + + for (size_t t = 0; !done; t++) { + if (readconf) { + readconf = 0; + conf_parse(configfile); + } + switch (poll(pfd, (nfds_t)nfd, tout)) { + case -1: + if (errno == EINTR) + continue; + (*lfun)(LOG_ERR, "poll (%m)"); + return EXIT_FAILURE; + case 0: + state_sync(state); + break; + default: + for (size_t i = 0; i < nfd; i++) + if (pfd[i].revents & POLLIN) + process(bl[i]); + } + if (t % 100 == 0) + state_sync(state); + if (t % 10000 == 0) + update_interfaces(); + update(); + } + state_close(state); + return 0; +} diff --git a/contrib/blacklist/bin/blacklistd.conf.5 b/contrib/blacklist/bin/blacklistd.conf.5 new file mode 100644 index 0000000..40d507b --- /dev/null +++ b/contrib/blacklist/bin/blacklistd.conf.5 @@ -0,0 +1,222 @@ +.\" $NetBSD: blacklistd.conf.5,v 1.3 2015/04/30 06:20:43 riz Exp $ +.\" +.\" Copyright (c) 2015 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Christos Zoulas. +.\" +.\" 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd April 29, 2015 +.Dt BLACKLISTD.CONF 5 +.Os +.Sh NAME +.Nm blacklistd.conf +.Nd configuration file format for blacklistd +.Sh DESCRIPTION +The +.Nm +files contains configuration lines for +.Xr blacklistd 8 . +It contains one entry per line, and is similar to +.Xr inetd.conf 5 . +There must be an entry for each field of the configuration file, with +entries for each field separated by a tab or a space. +Comments are denoted by a +.Dq # +at the beginning of a line. +.Pp +There are two kinds of configuration lines, +.Va local +and +.Va remote . +By default, configuration lines are +.Va local , +i.e. the address specified refers to the addresses on the local machine. +To switch to between +.Va local +and +.Va remote +configuration lines you can specify the stanzas: +.Dq [local] +and +.Dq [remote] . +.Pp +On +.Va local +and +.Va remote +lines +.Dq * +means use the default, or wildcard match. +In addition, for +.Va remote +lines +.Dq = +means use the values from the matched +.Va local +configuration line. +.Pp +The first four fields, +.Va location , +.Va type , +.Va proto , +and +.Va owner +are used to match the +.Va local +or +.Va remote +addresses, whereas the last 3 fields +.Va name , +.Va nfail , +and +.Va disable +are used to modify the filtering action. +.Pp +The first field denotes the +.Va location +as an address, mask, and port. +The syntax for the +.Va location +is: +.Bd -literal -offset indent + [<address>|<interface>][/<mask>][:<port>] +.Ed +.Pp +The +.Dv address +can be an IPv4 address in numeric format, an IPv6 address +in numeric format and enclosed by square brackets, or an interface name. +Mask modifiers are not allowed on interfaces because interfaces +have multiple address in different protocols where the mask has a different +size. +.Pp +The +.Dv mask +is always numeric, but the +.Dv port +can be either numeric or symbolic. +.Pp +The second field is the socket +.Va type : +.Dv stream , +.Dv dgram , +or numeric. +The third field is the +.Va prococol : +.Dv tcp , +.Dv udp , +.Dv tcp6 , +.Dv udp6 , +or numeric. +The fourth file is the effective user +.Va ( owner ) +of the daemon process reporting the event, +either as a username or a userid. +.Pp +The rest of the fields are controlling the behavior of the filter. +.Pp +The +.Va name +field, is the name of the packet filter rule to be used. +If the +.Va name +starts with a +.Dq - , +then the default rulename is prepended to the given name. +If the +.Dv name +contains a +.Dq / , +the remaining portion of the name is interpreted as the mask to be +applied to the address specified in the rule, so one can block whole +subnets for a single rule violation. +.Pp +The +.Va nfail +field contains the number of failed attempts before access is blocked, +defaulting to +.Dq * +meaning never, and the last field +.Va disable +specifies the amount of time since the last access that the blocking +rule should be active, defaulting to +.Dq * +meaning forever. +The default unit for +.Va disable +is seconds, but one can specify suffixes for different units, such as +.Dq m +for minutes +.Dq h +for hours and +.Dq d +for days. +.Pp +Matching is done first by checking the +.Va local +rules one by one, from the most specific to the least specific. +If a match is found, then the +.Va remote +rules are applied, and if a match is found the +.Va name , +.Va nfail , +and +.Va disable +fields can be altered by the +.Va remote +rule that matched. +.Pp +The +.Va remote +rules can be used for whitelisting specific addresses, changing the mask +size, or the rule that the packet filter uses, the number of failed attempts, +or the blocked duration. +.Sh FILES +.Bl -tag -width /etc/blacklistd.conf -compact +.It Pa /etc/blacklistd.conf +Configuration file. +.El +.Sh EXAMPLES +.Bd -literal -offset +# Block ssh, after 3 attempts for 6 hours on the bnx0 interface +[local] +# location type proto owner name nfail duration +bnx0:ssh * * * * 3 6h +[remote] +# Never block 1.2.3.4 +1.2.3.4:ssh * * * * * * +# For addresses coming from 8.8.0.0/16 block class C networks instead +# individual hosts, but keep the rest of the blocking parameters the same. +8.8.0.0/16:ssh * * * /24 = = +.Ed +.Sh SEE ALSO +.Xr blacklistctl 8 , +.Xr blacklistd 8 +.Sh HISTORY +.Nm +appeared in +.Nx 7 . +.Sh AUTHORS +.An Christos Zoulas diff --git a/contrib/blacklist/bin/conf.c b/contrib/blacklist/bin/conf.c new file mode 100644 index 0000000..3ec1e08 --- /dev/null +++ b/contrib/blacklist/bin/conf.c @@ -0,0 +1,1142 @@ +/* $NetBSD: conf.c,v 1.24 2016/04/04 15:52:56 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: conf.c,v 1.24 2016/04/04 15:52:56 christos Exp $"); + +#include <stdio.h> +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif +#ifdef HAVE_UTIL_H +#include <util.h> +#endif +#include <string.h> +#include <ctype.h> +#include <inttypes.h> +#include <netdb.h> +#include <pwd.h> +#include <syslog.h> +#include <errno.h> +#include <stdlib.h> +#include <limits.h> +#include <ifaddrs.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <net/if.h> +#include <sys/socket.h> + +#include "bl.h" +#include "internal.h" +#include "support.h" +#include "conf.h" + + +struct sockaddr_if { + uint8_t sif_len; + sa_family_t sif_family; + in_port_t sif_port; + char sif_name[16]; +}; + +#define SIF_NAME(a) \ + ((const struct sockaddr_if *)(const void *)(a))->sif_name + +static int conf_is_interface(const char *); + +#define FSTAR -1 +#define FEQUAL -2 + +static void +advance(char **p) +{ + char *ep = *p; + while (*ep && !isspace((unsigned char)*ep)) + ep++; + while (*ep && isspace((unsigned char)*ep)) + *ep++ = '\0'; + *p = ep; +} + +static int +getnum(const char *f, size_t l, bool local, void *rp, const char *name, + const char *p) +{ + int e; + intmax_t im; + int *r = rp; + + if (strcmp(p, "*") == 0) { + *r = FSTAR; + return 0; + } + if (strcmp(p, "=") == 0) { + if (local) + goto out; + *r = FEQUAL; + return 0; + } + + im = strtoi(p, NULL, 0, 0, INT_MAX, &e); + if (e == 0) { + *r = (int)im; + return 0; + } + + if (f == NULL) + return -1; + (*lfun)(LOG_ERR, "%s: %s, %zu: Bad number for %s [%s]", __func__, f, l, + name, p); + return -1; +out: + (*lfun)(LOG_ERR, "%s: %s, %zu: `=' for %s not allowed in local config", + __func__, f, l, name); + return -1; + +} + +static int +getnfail(const char *f, size_t l, bool local, struct conf *c, const char *p) +{ + return getnum(f, l, local, &c->c_nfail, "nfail", p); +} + +static int +getsecs(const char *f, size_t l, bool local, struct conf *c, const char *p) +{ + int e; + char *ep; + intmax_t tot, im; + + tot = 0; + if (strcmp(p, "*") == 0) { + c->c_duration = FSTAR; + return 0; + } + if (strcmp(p, "=") == 0) { + if (local) + goto out; + c->c_duration = FEQUAL; + return 0; + } +again: + im = strtoi(p, &ep, 0, 0, INT_MAX, &e); + + if (e == ENOTSUP) { + switch (*ep) { + case 'd': + im *= 24; + /*FALLTHROUGH*/ + case 'h': + im *= 60; + /*FALLTHROUGH*/ + case 'm': + im *= 60; + /*FALLTHROUGH*/ + case 's': + e = 0; + tot += im; + if (ep[1] != '\0') { + p = ep + 2; + goto again; + } + break; + } + } else + tot = im; + + if (e == 0) { + c->c_duration = (int)tot; + return 0; + } + + if (f == NULL) + return -1; + (*lfun)(LOG_ERR, "%s: %s, %zu: Bad number [%s]", __func__, f, l, p); + return -1; +out: + (*lfun)(LOG_ERR, "%s: %s, %zu: `=' duration not allowed in local" + " config", __func__, f, l); + return -1; + +} + +static int +getport(const char *f, size_t l, bool local, void *r, const char *p) +{ + struct servent *sv; + + // XXX: Pass in the proto instead + if ((sv = getservbyname(p, "tcp")) != NULL) { + *(int *)r = ntohs(sv->s_port); + return 0; + } + if ((sv = getservbyname(p, "udp")) != NULL) { + *(int *)r = ntohs(sv->s_port); + return 0; + } + + return getnum(f, l, local, r, "service", p); +} + +static int +getmask(const char *f, size_t l, bool local, const char **p, int *mask) +{ + char *d; + const char *s = *p; + + if ((d = strchr(s, ':')) != NULL) { + *d++ = '\0'; + *p = d; + } + if ((d = strchr(s, '/')) == NULL) { + *mask = FSTAR; + return 0; + } + + *d++ = '\0'; + return getnum(f, l, local, mask, "mask", d); +} + +static int +gethostport(const char *f, size_t l, bool local, struct conf *c, const char *p) +{ + char *d; // XXX: Ok to write to string. + in_port_t *port = NULL; + const char *pstr; + + if (strcmp(p, "*") == 0) { + c->c_port = FSTAR; + c->c_lmask = FSTAR; + return 0; + } + + if ((d = strchr(p, ']')) != NULL) { + *d++ = '\0'; + pstr = d; + p++; + } else + pstr = p; + + if (getmask(f, l, local, &pstr, &c->c_lmask) == -1) + goto out; + + if (d) { + struct sockaddr_in6 *sin6 = (void *)&c->c_ss; + if (debug) + (*lfun)(LOG_DEBUG, "%s: host6 %s", __func__, p); + if (strcmp(p, "*") != 0) { + if (inet_pton(AF_INET6, p, &sin6->sin6_addr) == -1) + goto out; + sin6->sin6_family = AF_INET6; +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + sin6->sin6_len = sizeof(*sin6); +#endif + port = &sin6->sin6_port; + } + } else if (pstr != p || strchr(p, '.') || conf_is_interface(p)) { + if (pstr == p) + pstr = "*"; + struct sockaddr_in *sin = (void *)&c->c_ss; + struct sockaddr_if *sif = (void *)&c->c_ss; + if (debug) + (*lfun)(LOG_DEBUG, "%s: host4 %s", __func__, p); + if (strcmp(p, "*") != 0) { + if (conf_is_interface(p)) { + if (!local) + goto out2; + if (debug) + (*lfun)(LOG_DEBUG, "%s: interface %s", + __func__, p); + if (c->c_lmask != FSTAR) + goto out1; + sif->sif_family = AF_MAX; + strlcpy(sif->sif_name, p, + sizeof(sif->sif_name)); +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + sif->sif_len = sizeof(*sif); +#endif + port = &sif->sif_port; + } else if (inet_pton(AF_INET, p, &sin->sin_addr) != -1) + { + sin->sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + sin->sin_len = sizeof(*sin); +#endif + port = &sin->sin_port; + } else + goto out; + } + } + + if (getport(f, l, local, &c->c_port, pstr) == -1) + return -1; + + if (port && c->c_port != FSTAR && c->c_port != FEQUAL) + *port = htons((in_port_t)c->c_port); + return 0; +out: + (*lfun)(LOG_ERR, "%s: %s, %zu: Bad address [%s]", __func__, f, l, pstr); + return -1; +out1: + (*lfun)(LOG_ERR, "%s: %s, %zu: Can't specify mask %d with " + "interface [%s]", __func__, f, l, c->c_lmask, p); + return -1; +out2: + (*lfun)(LOG_ERR, "%s: %s, %zu: Interface spec does not make sense " + "with remote config [%s]", __func__, f, l, p); + return -1; +} + +static int +getproto(const char *f, size_t l, bool local __unused, struct conf *c, + const char *p) +{ + if (strcmp(p, "stream") == 0) { + c->c_proto = IPPROTO_TCP; + return 0; + } + if (strcmp(p, "dgram") == 0) { + c->c_proto = IPPROTO_UDP; + return 0; + } + return getnum(f, l, local, &c->c_proto, "protocol", p); +} + +static int +getfamily(const char *f, size_t l, bool local __unused, struct conf *c, + const char *p) +{ + if (strncmp(p, "tcp", 3) == 0 || strncmp(p, "udp", 3) == 0) { + c->c_family = p[3] == '6' ? AF_INET6 : AF_INET; + return 0; + } + return getnum(f, l, local, &c->c_family, "family", p); +} + +static int +getuid(const char *f, size_t l, bool local __unused, struct conf *c, + const char *p) +{ + struct passwd *pw; + + if ((pw = getpwnam(p)) != NULL) { + c->c_uid = (int)pw->pw_uid; + return 0; + } + + return getnum(f, l, local, &c->c_uid, "user", p); +} + + +static int +getname(const char *f, size_t l, bool local, struct conf *c, + const char *p) +{ + if (getmask(f, l, local, &p, &c->c_rmask) == -1) + return -1; + + if (strcmp(p, "*") == 0) { + strlcpy(c->c_name, rulename, CONFNAMESZ); + return 0; + } + if (strcmp(p, "=") == 0) { + if (local) + goto out; + c->c_name[0] = '\0'; + return 0; + } + + snprintf(c->c_name, CONFNAMESZ, "%s%s", *p == '-' ? rulename : "", p); + return 0; +out: + (*lfun)(LOG_ERR, "%s: %s, %zu: `=' name not allowed in local" + " config", __func__, f, l); + return -1; +} + +static int +getvalue(const char *f, size_t l, bool local, void *r, char **p, + int (*fun)(const char *, size_t, bool, struct conf *, const char *)) +{ + char *ep = *p; + + advance(p); + return (*fun)(f, l, local, r, ep); +} + + +static int +conf_parseline(const char *f, size_t l, char *p, struct conf *c, bool local) +{ + int e; + + while (*p && isspace((unsigned char)*p)) + p++; + + memset(c, 0, sizeof(*c)); + e = getvalue(f, l, local, c, &p, gethostport); + if (e) return -1; + e = getvalue(f, l, local, c, &p, getproto); + if (e) return -1; + e = getvalue(f, l, local, c, &p, getfamily); + if (e) return -1; + e = getvalue(f, l, local, c, &p, getuid); + if (e) return -1; + e = getvalue(f, l, local, c, &p, getname); + if (e) return -1; + e = getvalue(f, l, local, c, &p, getnfail); + if (e) return -1; + e = getvalue(f, l, local, c, &p, getsecs); + if (e) return -1; + + return 0; +} + +static int +conf_sort(const void *v1, const void *v2) +{ + const struct conf *c1 = v1; + const struct conf *c2 = v2; + +#define CMP(a, b, f) \ + if ((a)->f > (b)->f) return -1; \ + else if ((a)->f < (b)->f) return 1 + + CMP(c1, c2, c_ss.ss_family); + CMP(c1, c2, c_lmask); + CMP(c1, c2, c_port); + CMP(c1, c2, c_proto); + CMP(c1, c2, c_family); + CMP(c1, c2, c_rmask); + CMP(c1, c2, c_uid); +#undef CMP + return 0; +} + +static int +conf_is_interface(const char *name) +{ + const struct ifaddrs *ifa; + + for (ifa = ifas; ifa; ifa = ifa->ifa_next) + if (strcmp(ifa->ifa_name, name) == 0) + return 1; + return 0; +} + +#define MASK(m) ((uint32_t)~((1 << (32 - (m))) - 1)) + +static int +conf_amask_eq(const void *v1, const void *v2, size_t len, int mask) +{ + const uint32_t *a1 = v1; + const uint32_t *a2 = v2; + uint32_t m; + int omask = mask; + + len >>= 2; + switch (mask) { + case FSTAR: + if (memcmp(v1, v2, len) == 0) + return 1; + goto out; + case FEQUAL: + + (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__, + mask); + abort(); + default: + break; + } + + for (size_t i = 0; i < len; i++) { + if (mask > 32) { + m = htonl((uint32_t)~0); + mask -= 32; + } else if (mask) { + m = htonl(MASK(mask)); + mask = 0; + } else + return 1; + if ((a1[i] & m) != (a2[i] & m)) + goto out; + } + return 1; +out: + if (debug > 1) { + char b1[256], b2[256]; + len <<= 2; + blhexdump(b1, sizeof(b1), "a1", v1, len); + blhexdump(b2, sizeof(b2), "a2", v2, len); + (*lfun)(LOG_DEBUG, "%s: %s != %s [0x%x]", __func__, + b1, b2, omask); + } + return 0; +} + +/* + * Apply the mask to the given address + */ +static void +conf_apply_mask(void *v, size_t len, int mask) +{ + uint32_t *a = v; + uint32_t m; + + switch (mask) { + case FSTAR: + return; + case FEQUAL: + (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__, + mask); + abort(); + default: + break; + } + len >>= 2; + + for (size_t i = 0; i < len; i++) { + if (mask > 32) { + m = htonl((uint32_t)~0); + mask -= 32; + } else if (mask) { + m = htonl(MASK(mask)); + mask = 0; + } else + m = 0; + a[i] &= m; + } +} + +/* + * apply the mask and the port to the address given + */ +static void +conf_addr_set(struct conf *c, const struct sockaddr_storage *ss) +{ + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + in_port_t *port; + void *addr; + size_t alen; + + c->c_lmask = c->c_rmask; + c->c_ss = *ss; + + if (c->c_ss.ss_family != c->c_family) { + (*lfun)(LOG_CRIT, "%s: Internal error: mismatched family " + "%u != %u", __func__, c->c_ss.ss_family, c->c_family); + abort(); + } + + switch (c->c_ss.ss_family) { + case AF_INET: + sin = (void *)&c->c_ss; + port = &sin->sin_port; + addr = &sin->sin_addr; + alen = sizeof(sin->sin_addr); + break; + case AF_INET6: + sin6 = (void *)&c->c_ss; + port = &sin6->sin6_port; + addr = &sin6->sin6_addr; + alen = sizeof(sin6->sin6_addr); + break; + default: + (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u", + __func__, c->c_ss.ss_family); + abort(); + } + + *port = htons((in_port_t)c->c_port); + conf_apply_mask(addr, alen, c->c_lmask); + if (c->c_lmask == FSTAR) + c->c_lmask = (int)(alen * 8); + if (debug) { + char buf[128]; + sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&c->c_ss); + (*lfun)(LOG_DEBUG, "Applied address %s", buf); + } +} + +/* + * Compared two addresses for equality applying the mask + */ +static int +conf_inet_eq(const void *v1, const void *v2, int mask) +{ + const struct sockaddr *sa1 = v1; + const struct sockaddr *sa2 = v2; + size_t size; + + if (sa1->sa_family != sa2->sa_family) + return 0; + + switch (sa1->sa_family) { + case AF_INET: { + const struct sockaddr_in *s1 = v1; + const struct sockaddr_in *s2 = v2; + size = sizeof(s1->sin_addr); + v1 = &s1->sin_addr; + v2 = &s2->sin_addr; + break; + } + + case AF_INET6: { + const struct sockaddr_in6 *s1 = v1; + const struct sockaddr_in6 *s2 = v2; + size = sizeof(s1->sin6_addr); + v1 = &s1->sin6_addr; + v2 = &s2->sin6_addr; + break; + } + + default: + (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u", + __func__, sa1->sa_family); + abort(); + } + + return conf_amask_eq(v1, v2, size, mask); +} + +static int +conf_addr_in_interface(const struct sockaddr_storage *s1, + const struct sockaddr_storage *s2, int mask) +{ + const char *name = SIF_NAME(s2); + const struct ifaddrs *ifa; + + for (ifa = ifas; ifa; ifa = ifa->ifa_next) { + if ((ifa->ifa_flags & IFF_UP) == 0) + continue; + + if (strcmp(ifa->ifa_name, name) != 0) + continue; + + if (s1->ss_family != ifa->ifa_addr->sa_family) + continue; + + bool eq; + switch (s1->ss_family) { + case AF_INET: + case AF_INET6: + eq = conf_inet_eq(ifa->ifa_addr, s1, mask); + break; + default: + (*lfun)(LOG_ERR, "Bad family %u", s1->ss_family); + continue; + } + if (eq) + return 1; + } + return 0; +} + +static int +conf_addr_eq(const struct sockaddr_storage *s1, + const struct sockaddr_storage *s2, int mask) +{ + switch (s2->ss_family) { + case 0: + return 1; + case AF_MAX: + return conf_addr_in_interface(s1, s2, mask); + case AF_INET: + case AF_INET6: + return conf_inet_eq(s1, s2, mask); + default: + (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u", + __func__, s1->ss_family); + abort(); + } +} + +static int +conf_eq(const struct conf *c1, const struct conf *c2) +{ + + if (!conf_addr_eq(&c1->c_ss, &c2->c_ss, c2->c_lmask)) + return 0; + +#define CMP(a, b, f) \ + if ((a)->f != (b)->f && (b)->f != FSTAR && (b)->f != FEQUAL) { \ + if (debug > 1) \ + (*lfun)(LOG_DEBUG, "%s: %s fail %d != %d", __func__, \ + __STRING(f), (a)->f, (b)->f); \ + return 0; \ + } + CMP(c1, c2, c_port); + CMP(c1, c2, c_proto); + CMP(c1, c2, c_family); + CMP(c1, c2, c_uid); +#undef CMP + return 1; +} + +static const char * +conf_num(char *b, size_t l, int n) +{ + switch (n) { + case FSTAR: + return "*"; + case FEQUAL: + return "="; + default: + snprintf(b, l, "%d", n); + return b; + } +} + +static const char * +fmtname(const char *n) { + size_t l = strlen(rulename); + if (l == 0) + return "*"; + if (strncmp(n, rulename, l) == 0) { + if (n[l] != '\0') + return n + l; + else + return "*"; + } else if (!*n) + return "="; + else + return n; +} + +static void +fmtport(char *b, size_t l, int port) +{ + char buf[128]; + + if (port == FSTAR) + return; + + if (b[0] == '\0' || strcmp(b, "*") == 0) + snprintf(b, l, "%d", port); + else { + snprintf(buf, sizeof(buf), ":%d", port); + strlcat(b, buf, l); + } +} + +static const char * +fmtmask(char *b, size_t l, int fam, int mask) +{ + char buf[128]; + + switch (mask) { + case FSTAR: + return ""; + case FEQUAL: + if (strcmp(b, "=") == 0) + return ""; + else { + strlcat(b, "/=", l); + return b; + } + default: + break; + } + + switch (fam) { + case AF_INET: + if (mask == 32) + return ""; + break; + case AF_INET6: + if (mask == 128) + return ""; + break; + default: + break; + } + + snprintf(buf, sizeof(buf), "/%d", mask); + strlcat(b, buf, l); + return b; +} + +static const char * +conf_namemask(char *b, size_t l, const struct conf *c) +{ + strlcpy(b, fmtname(c->c_name), l); + fmtmask(b, l, c->c_family, c->c_rmask); + return b; +} + +const char * +conf_print(char *buf, size_t len, const char *pref, const char *delim, + const struct conf *c) +{ + char ha[128], hb[32], b[5][64]; + int sp; + +#define N(n, v) conf_num(b[n], sizeof(b[n]), (v)) + + switch (c->c_ss.ss_family) { + case 0: + snprintf(ha, sizeof(ha), "*"); + break; + case AF_MAX: + snprintf(ha, sizeof(ha), "%s", SIF_NAME(&c->c_ss)); + break; + default: + sockaddr_snprintf(ha, sizeof(ha), "%a", (const void *)&c->c_ss); + break; + } + + fmtmask(ha, sizeof(ha), c->c_family, c->c_lmask); + fmtport(ha, sizeof(ha), c->c_port); + + sp = *delim == '\t' ? 20 : -1; + hb[0] = '\0'; + if (*delim) + snprintf(buf, len, "%s%*.*s%s%s%s" "%s%s%s%s" + "%s%s" "%s%s%s", + pref, sp, sp, ha, delim, N(0, c->c_proto), delim, + N(1, c->c_family), delim, N(2, c->c_uid), delim, + conf_namemask(hb, sizeof(hb), c), delim, + N(3, c->c_nfail), delim, N(4, c->c_duration)); + else + snprintf(buf, len, "%starget:%s, proto:%s, family:%s, " + "uid:%s, name:%s, nfail:%s, duration:%s", pref, + ha, N(0, c->c_proto), N(1, c->c_family), N(2, c->c_uid), + conf_namemask(hb, sizeof(hb), c), + N(3, c->c_nfail), N(4, c->c_duration)); + return buf; +} + +/* + * Apply the local config match to the result + */ +static void +conf_apply(struct conf *c, const struct conf *sc) +{ + char buf[BUFSIZ]; + + if (debug) { + (*lfun)(LOG_DEBUG, "%s: %s", __func__, + conf_print(buf, sizeof(buf), "merge:\t", "", sc)); + (*lfun)(LOG_DEBUG, "%s: %s", __func__, + conf_print(buf, sizeof(buf), "to:\t", "", c)); + } + memcpy(c->c_name, sc->c_name, CONFNAMESZ); + c->c_uid = sc->c_uid; + c->c_rmask = sc->c_rmask; + c->c_nfail = sc->c_nfail; + c->c_duration = sc->c_duration; + + if (debug) + (*lfun)(LOG_DEBUG, "%s: %s", __func__, + conf_print(buf, sizeof(buf), "result:\t", "", c)); +} + +/* + * Merge a remote configuration to the result + */ +static void +conf_merge(struct conf *c, const struct conf *sc) +{ + char buf[BUFSIZ]; + + if (debug) { + (*lfun)(LOG_DEBUG, "%s: %s", __func__, + conf_print(buf, sizeof(buf), "merge:\t", "", sc)); + (*lfun)(LOG_DEBUG, "%s: %s", __func__, + conf_print(buf, sizeof(buf), "to:\t", "", c)); + } + + if (sc->c_name[0]) + memcpy(c->c_name, sc->c_name, CONFNAMESZ); + if (sc->c_uid != FEQUAL) + c->c_uid = sc->c_uid; + if (sc->c_rmask != FEQUAL) + c->c_lmask = c->c_rmask = sc->c_rmask; + if (sc->c_nfail != FEQUAL) + c->c_nfail = sc->c_nfail; + if (sc->c_duration != FEQUAL) + c->c_duration = sc->c_duration; + if (debug) + (*lfun)(LOG_DEBUG, "%s: %s", __func__, + conf_print(buf, sizeof(buf), "result:\t", "", c)); +} + +static void +confset_init(struct confset *cs) +{ + cs->cs_c = NULL; + cs->cs_n = 0; + cs->cs_m = 0; +} + +static int +confset_grow(struct confset *cs) +{ + void *tc; + + cs->cs_m += 10; + tc = realloc(cs->cs_c, cs->cs_m * sizeof(*cs->cs_c)); + if (tc == NULL) { + (*lfun)(LOG_ERR, "%s: Can't grow confset (%m)", __func__); + return -1; + } + cs->cs_c = tc; + return 0; +} + +static struct conf * +confset_get(struct confset *cs) +{ + return &cs->cs_c[cs->cs_n]; +} + +static bool +confset_full(const struct confset *cs) +{ + return cs->cs_n == cs->cs_m; +} + +static void +confset_sort(struct confset *cs) +{ + qsort(cs->cs_c, cs->cs_n, sizeof(*cs->cs_c), conf_sort); +} + +static void +confset_add(struct confset *cs) +{ + cs->cs_n++; +} + +static void +confset_free(struct confset *cs) +{ + free(cs->cs_c); + confset_init(cs); +} + +static void +confset_replace(struct confset *dc, struct confset *sc) +{ + struct confset tc; + tc = *dc; + *dc = *sc; + confset_init(sc); + confset_free(&tc); +} + +static void +confset_list(const struct confset *cs, const char *msg, const char *where) +{ + char buf[BUFSIZ]; + + (*lfun)(LOG_DEBUG, "[%s]", msg); + (*lfun)(LOG_DEBUG, "%20.20s\ttype\tproto\towner\tname\tnfail\tduration", + where); + for (size_t i = 0; i < cs->cs_n; i++) + (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), "", "\t", + &cs->cs_c[i])); +} + +/* + * Match a configuration against the given list and apply the function + * to it, returning the matched entry number. + */ +static size_t +confset_match(const struct confset *cs, struct conf *c, + void (*fun)(struct conf *, const struct conf *)) +{ + char buf[BUFSIZ]; + size_t i; + + for (i = 0; i < cs->cs_n; i++) { + if (debug) + (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), + "check:\t", "", &cs->cs_c[i])); + if (conf_eq(c, &cs->cs_c[i])) { + if (debug) + (*lfun)(LOG_DEBUG, "%s", + conf_print(buf, sizeof(buf), + "found:\t", "", &cs->cs_c[i])); + (*fun)(c, &cs->cs_c[i]); + break; + } + } + return i; +} + +const struct conf * +conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss, + struct conf *cr) +{ + int proto; + socklen_t slen; + struct sockaddr_storage lss; + size_t i; + char buf[BUFSIZ]; + + memset(cr, 0, sizeof(*cr)); + slen = sizeof(lss); + memset(&lss, 0, slen); + if (getsockname(fd, (void *)&lss, &slen) == -1) { + (*lfun)(LOG_ERR, "getsockname failed (%m)"); + return NULL; + } + + slen = sizeof(proto); + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &proto, &slen) == -1) { + (*lfun)(LOG_ERR, "getsockopt failed (%m)"); + return NULL; + } + + if (debug) { + sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&lss); + (*lfun)(LOG_DEBUG, "listening socket: %s", buf); + } + + switch (proto) { + case SOCK_STREAM: + cr->c_proto = IPPROTO_TCP; + break; + case SOCK_DGRAM: + cr->c_proto = IPPROTO_UDP; + break; + default: + (*lfun)(LOG_ERR, "unsupported protocol %d", proto); + return NULL; + } + + switch (lss.ss_family) { + case AF_INET: + cr->c_port = ntohs(((struct sockaddr_in *)&lss)->sin_port); + break; + case AF_INET6: + cr->c_port = ntohs(((struct sockaddr_in6 *)&lss)->sin6_port); + break; + default: + (*lfun)(LOG_ERR, "unsupported family %d", lss.ss_family); + return NULL; + } + + cr->c_ss = lss; + cr->c_lmask = FSTAR; + cr->c_uid = (int)uid; + cr->c_family = lss.ss_family; + cr->c_name[0] = '\0'; + cr->c_rmask = FSTAR; + cr->c_nfail = FSTAR; + cr->c_duration = FSTAR; + + if (debug) + (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), + "look:\t", "", cr)); + + /* match the local config */ + i = confset_match(&lconf, cr, conf_apply); + if (i == lconf.cs_n) { + if (debug) + (*lfun)(LOG_DEBUG, "not found"); + return NULL; + } + + conf_addr_set(cr, rss); + /* match the remote config */ + confset_match(&rconf, cr, conf_merge); + /* to apply the mask */ + conf_addr_set(cr, &cr->c_ss); + + return cr; +} + + +void +conf_parse(const char *f) +{ + FILE *fp; + char *line; + size_t lineno, len; + struct confset lc, rc, *cs; + + if ((fp = fopen(f, "r")) == NULL) { + (*lfun)(LOG_ERR, "%s: Cannot open `%s' (%m)", __func__, f); + return; + } + + lineno = 1; + + confset_init(&rc); + confset_init(&lc); + cs = &lc; + for (; (line = fparseln(fp, &len, &lineno, NULL, 0)) != NULL; + free(line)) + { + if (!*line) + continue; + if (strcmp(line, "[local]") == 0) { + cs = &lc; + continue; + } + if (strcmp(line, "[remote]") == 0) { + cs = &rc; + continue; + } + + if (confset_full(cs)) { + if (confset_grow(cs) == -1) { + confset_free(&lc); + confset_free(&rc); + fclose(fp); + return; + } + } + if (conf_parseline(f, lineno, line, confset_get(cs), + cs == &lc) == -1) + continue; + confset_add(cs); + } + + fclose(fp); + confset_sort(&lc); + confset_sort(&rc); + + confset_replace(&rconf, &rc); + confset_replace(&lconf, &lc); + + if (debug) { + confset_list(&lconf, "local", "target"); + confset_list(&rconf, "remote", "source"); + } +} diff --git a/contrib/blacklist/bin/conf.h b/contrib/blacklist/bin/conf.h new file mode 100644 index 0000000..03f1942 --- /dev/null +++ b/contrib/blacklist/bin/conf.h @@ -0,0 +1,65 @@ +/* $NetBSD: conf.h,v 1.6 2015/01/27 19:40:36 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifndef _CONF_H +#define _CONF_H + +#include <sys/socket.h> + +struct conf { + struct sockaddr_storage c_ss; + int c_lmask; + int c_port; + int c_proto; + int c_family; + int c_uid; + int c_nfail; + char c_name[128]; + int c_rmask; + int c_duration; +}; + +struct confset { + struct conf *cs_c; + size_t cs_n; + size_t cs_m; +}; + +#define CONFNAMESZ sizeof(((struct conf *)0)->c_name) + +__BEGIN_DECLS +const char *conf_print(char *, size_t, const char *, const char *, + const struct conf *); +void conf_parse(const char *); +const struct conf *conf_find(int, uid_t, const struct sockaddr_storage *, + struct conf *); +__END_DECLS + +#endif /* _CONF_H */ diff --git a/contrib/blacklist/bin/internal.c b/contrib/blacklist/bin/internal.c new file mode 100644 index 0000000..5c039e4 --- /dev/null +++ b/contrib/blacklist/bin/internal.c @@ -0,0 +1,48 @@ +/* $NetBSD: internal.c,v 1.5 2015/01/27 19:40:37 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: internal.c,v 1.5 2015/01/27 19:40:37 christos Exp $"); + +#include <stdio.h> +#include <syslog.h> +#include "conf.h" +#include "internal.h" + +int debug; +const char *rulename = "blacklistd"; +const char *controlprog = _PATH_BLCONTROL; +struct confset lconf, rconf; +struct ifaddrs *ifas; +void (*lfun)(int, const char *, ...) = syslog; diff --git a/contrib/blacklist/bin/internal.h b/contrib/blacklist/bin/internal.h new file mode 100644 index 0000000..5a40e49 --- /dev/null +++ b/contrib/blacklist/bin/internal.h @@ -0,0 +1,57 @@ +/* $NetBSD: internal.h,v 1.14 2016/04/04 15:52:56 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifndef _INTERNAL_H +#define _INTERNAL_H + +#ifndef _PATH_BLCONF +#define _PATH_BLCONF "/etc/blacklistd.conf" +#endif +#ifndef _PATH_BLCONTROL +#define _PATH_BLCONTROL "/libexec/blacklistd-helper" +#endif +#ifndef _PATH_BLSTATE +#define _PATH_BLSTATE "/var/db/blacklistd.db" +#endif + +extern struct confset rconf, lconf; +extern int debug; +extern const char *rulename; +extern const char *controlprog; +extern struct ifaddrs *ifas; + +#if !defined(__syslog_attribute__) && !defined(__syslog__) +#define __syslog__ __printf__ +#endif + +extern void (*lfun)(int, const char *, ...) + __attribute__((__format__(__syslog__, 2, 3))); + +#endif /* _INTERNAL_H */ diff --git a/contrib/blacklist/bin/run.c b/contrib/blacklist/bin/run.c new file mode 100644 index 0000000..8499edd --- /dev/null +++ b/contrib/blacklist/bin/run.c @@ -0,0 +1,156 @@ +/* $NetBSD: run.c,v 1.14 2016/04/04 15:52:56 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: run.c,v 1.14 2016/04/04 15:52:56 christos Exp $"); + +#include <stdio.h> +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif +#ifdef HAVE_UTIL_H +#include <util.h> +#endif +#include <stdarg.h> +#include <limits.h> +#include <stdlib.h> +#include <inttypes.h> +#include <syslog.h> +#include <string.h> +#include <netinet/in.h> +#include <net/if.h> + +#include "run.h" +#include "conf.h" +#include "internal.h" +#include "support.h" + +extern char **environ; + +static char * +run(const char *cmd, const char *name, ...) +{ + const char *argv[20]; + size_t i; + va_list ap; + FILE *fp; + char buf[10240], *res; + + argv[0] = "control"; + argv[1] = cmd; + argv[2] = name; + va_start(ap, name); + for (i = 3; i < __arraycount(argv) && + (argv[i] = va_arg(ap, char *)) != NULL; i++) + continue; + va_end(ap); + + if (debug) { + size_t z; + int r; + + r = snprintf(buf, sizeof(buf), "run %s [", controlprog); + if (r == -1 || (z = (size_t)r) >= sizeof(buf)) + z = sizeof(buf); + for (i = 0; argv[i]; i++) { + r = snprintf(buf + z, sizeof(buf) - z, "%s%s", + argv[i], argv[i + 1] ? " " : ""); + if (r == -1 || (z += (size_t)r) >= sizeof(buf)) + z = sizeof(buf); + } + (*lfun)(LOG_DEBUG, "%s]", buf); + } + + fp = popenve(controlprog, __UNCONST(argv), environ, "r"); + if (fp == NULL) { + (*lfun)(LOG_ERR, "popen %s failed (%m)", controlprog); + return NULL; + } + if (fgets(buf, sizeof(buf), fp) != NULL) + res = strdup(buf); + else + res = NULL; + pclose(fp); + if (debug) + (*lfun)(LOG_DEBUG, "%s returns %s", cmd, res); + return res; +} + +void +run_flush(const struct conf *c) +{ + free(run("flush", c->c_name, NULL)); +} + +int +run_change(const char *how, const struct conf *c, char *id, size_t len) +{ + const char *prname; + char poname[64], adname[128], maskname[32], *rv; + size_t off; + + switch (c->c_proto) { + case -1: + prname = ""; + break; + case IPPROTO_TCP: + prname = "tcp"; + break; + case IPPROTO_UDP: + prname = "udp"; + break; + default: + (*lfun)(LOG_ERR, "%s: bad protocol %d", __func__, c->c_proto); + return -1; + } + + if (c->c_port != -1) + snprintf(poname, sizeof(poname), "%d", c->c_port); + else + poname[0] = '\0'; + + snprintf(maskname, sizeof(maskname), "%d", c->c_lmask); + sockaddr_snprintf(adname, sizeof(adname), "%a", (const void *)&c->c_ss); + + rv = run(how, c->c_name, prname, adname, maskname, poname, id, NULL); + if (rv == NULL) + return -1; + if (len != 0) { + rv[strcspn(rv, "\n")] = '\0'; + off = strncmp(rv, "OK ", 3) == 0 ? 3 : 0; + strlcpy(id, rv + off, len); + } + free(rv); + return 0; +} diff --git a/contrib/blacklist/bin/run.h b/contrib/blacklist/bin/run.h new file mode 100644 index 0000000..bafc3e5 --- /dev/null +++ b/contrib/blacklist/bin/run.h @@ -0,0 +1,41 @@ +/* $NetBSD: run.h,v 1.5 2015/01/27 19:40:37 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifndef _RUN_H +#define _RUN_H + +__BEGIN_DECLS +struct conf; +void run_flush(const struct conf *); +struct sockaddr_storage; +int run_change(const char *, const struct conf *, char *, size_t); +__END_DECLS + +#endif /* _RUN_H */ diff --git a/contrib/blacklist/bin/state.c b/contrib/blacklist/bin/state.c new file mode 100644 index 0000000..eb97e97 --- /dev/null +++ b/contrib/blacklist/bin/state.c @@ -0,0 +1,233 @@ +/* $NetBSD: state.c,v 1.18 2016/04/04 15:52:56 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: state.c,v 1.18 2016/04/04 15:52:56 christos Exp $"); + +#include <sys/types.h> +#include <sys/socket.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <syslog.h> +#include <netinet/in.h> + +#include "bl.h" +#include "internal.h" +#include "conf.h" +#include "support.h" +#include "state.h" + +static HASHINFO openinfo = { + 4096, /* bsize */ + 32, /* ffactor */ + 256, /* nelem */ + 8 * 1024 * 1024,/* cachesize */ + NULL, /* hash() */ + 0 /* lorder */ +}; + +int +state_close(DB *db) +{ + if (db == NULL) + return -1; + if ((*db->close)(db) == -1) { + (*lfun)(LOG_ERR, "%s: can't close db (%m)", __func__); + return -1; + } + return 0; +} + +DB * +state_open(const char *dbname, int flags, mode_t perm) +{ + DB *db; + +#ifdef __APPLE__ + flags &= O_CREAT|O_EXCL|O_EXLOCK|O_NONBLOCK|O_RDONLY| + O_RDWR|O_SHLOCK|O_TRUNC; +#endif + db = dbopen(dbname, flags, perm, DB_HASH, &openinfo); + if (db == NULL) { + if (errno == ENOENT && (flags & O_CREAT) == 0) + return NULL; + (*lfun)(LOG_ERR, "%s: can't open `%s' (%m)", __func__, dbname); + } + return db; +} + +static int +state_sizecheck(const DBT *t) +{ + if (sizeof(struct conf) == t->size) + return 0; + (*lfun)(LOG_ERR, "Key size mismatch %zu != %zu", sizeof(struct conf), + t->size); + return -1; +} + +static void +dumpkey(const struct conf *k) +{ + char buf[10240]; + blhexdump(buf, sizeof(buf), __func__, k, sizeof(*k)); + (*lfun)(LOG_DEBUG, "%s", buf); + (*lfun)(LOG_DEBUG, "%s: %s", __func__, + conf_print(buf, sizeof(buf), "", "", k)); + +} + +int +state_del(DB *db, const struct conf *c) +{ + int rv; + DBT k; + + if (db == NULL) + return -1; + + k.data = __UNCONST(c); + k.size = sizeof(*c); + + switch (rv = (*db->del)(db, &k, 0)) { + case 0: + case 1: + if (debug > 1) { + (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); + (*db->sync)(db, 0); + } + return 0; + default: + (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); + return -1; + } +} + +int +state_get(DB *db, const struct conf *c, struct dbinfo *dbi) +{ + int rv; + DBT k, v; + + if (db == NULL) + return -1; + + k.data = __UNCONST(c); + k.size = sizeof(*c); + + switch (rv = (*db->get)(db, &k, &v, 0)) { + case 0: + case 1: + if (rv) + memset(dbi, 0, sizeof(*dbi)); + else + memcpy(dbi, v.data, sizeof(*dbi)); + if (debug > 1) + (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); + return 0; + default: + (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); + return -1; + } +} + +int +state_put(DB *db, const struct conf *c, const struct dbinfo *dbi) +{ + int rv; + DBT k, v; + + if (db == NULL) + return -1; + + k.data = __UNCONST(c); + k.size = sizeof(*c); + v.data = __UNCONST(dbi); + v.size = sizeof(*dbi); + + switch (rv = (*db->put)(db, &k, &v, 0)) { + case 0: + if (debug > 1) { + (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); + (*db->sync)(db, 0); + } + return 0; + case 1: + errno = EEXIST; + /*FALLTHROUGH*/ + default: + (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); + return -1; + } +} + +int +state_iterate(DB *db, struct conf *c, struct dbinfo *dbi, unsigned int first) +{ + int rv; + DBT k, v; + + if (db == NULL) + return -1; + + first = first ? R_FIRST : R_NEXT; + + switch (rv = (*db->seq)(db, &k, &v, first)) { + case 0: + if (state_sizecheck(&k) == -1) + return -1; + memcpy(c, k.data, sizeof(*c)); + if (debug > 2) + dumpkey(c); + memcpy(dbi, v.data, sizeof(*dbi)); + if (debug > 1) + (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); + return 1; + case 1: + if (debug > 1) + (*lfun)(LOG_DEBUG, "%s: returns %d", __func__, rv); + return 0; + default: + (*lfun)(LOG_ERR, "%s: failed (%m)", __func__); + return -1; + } +} + +int +state_sync(DB *db) +{ + return (*db->sync)(db, 0); +} diff --git a/contrib/blacklist/bin/state.h b/contrib/blacklist/bin/state.h new file mode 100644 index 0000000..2e92570 --- /dev/null +++ b/contrib/blacklist/bin/state.h @@ -0,0 +1,62 @@ +/* $NetBSD: state.h,v 1.5 2015/01/27 19:40:37 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifndef _STATE_H +#define _STATE_H + +#ifdef HAVE_DB_185_H +#include <db_185.h> +#elif HAVE_DB_H +#include <db.h> +#else +#error "no db.h" +#endif +#include <time.h> + +struct dbinfo { + int count; + time_t last; + char id[64]; +}; + +__BEGIN_DECLS +struct sockaddr_storage; +struct conf; + +DB *state_open(const char *, int, mode_t); +int state_close(DB *); +int state_get(DB *, const struct conf *, struct dbinfo *); +int state_put(DB *, const struct conf *, const struct dbinfo *); +int state_del(DB *, const struct conf *); +int state_iterate(DB *, struct conf *, struct dbinfo *, unsigned int); +int state_sync(DB *); +__END_DECLS + +#endif /* _STATE_H */ diff --git a/contrib/blacklist/bin/support.c b/contrib/blacklist/bin/support.c new file mode 100644 index 0000000..0dac499ac --- /dev/null +++ b/contrib/blacklist/bin/support.c @@ -0,0 +1,157 @@ +/* $NetBSD: support.c,v 1.8 2016/04/04 15:52:56 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: support.c,v 1.8 2016/04/04 15:52:56 christos Exp $"); + +#include <time.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> +#include <stdlib.h> +#include <inttypes.h> + +#include "support.h" + +static __attribute__((__format_arg__(3))) const char * +expandm(char *buf, size_t len, const char *fmt) +{ + char *p; + size_t r; + + if ((p = strstr(fmt, "%m")) == NULL) + return fmt; + + r = (size_t)(p - fmt); + if (r >= len) + return fmt; + + strlcpy(buf, fmt, r + 1); + strlcat(buf, strerror(errno), len); + strlcat(buf, fmt + r + 2, len); + + return buf; +} + +void +vdlog(int level __unused, const char *fmt, va_list ap) +{ + char buf[BUFSIZ]; + +// fprintf(stderr, "%s: ", getprogname()); + vfprintf(stderr, expandm(buf, sizeof(buf), fmt), ap); + fprintf(stderr, "\n"); +} + +void +dlog(int level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vdlog(level, fmt, ap); + va_end(ap); +} + +const char * +fmttime(char *b, size_t l, time_t t) +{ + struct tm tm; + if (localtime_r(&t, &tm) == NULL) + snprintf(b, l, "*%jd*", (intmax_t)t); + else + strftime(b, l, "%Y/%m/%d %H:%M:%S", &tm); + return b; +} + +const char * +fmtydhms(char *b, size_t l, time_t t) +{ + time_t s, m, h, d, y; + int z; + size_t o; + + s = t % 60; + t /= 60; + m = t % 60; + t /= 60; + h = t % 60; + t /= 24; + d = t % 24; + t /= 356; + y = t; + + z = 0; + o = 0; +#define APPEND(a) \ + if (a) { \ + z = snprintf(b + o, l - o, "%jd%s", (intmax_t)a, __STRING(a)); \ + if (z == -1) \ + return b; \ + o += (size_t)z; \ + if (o >= l) \ + return b; \ + } + APPEND(y) + APPEND(d) + APPEND(h) + APPEND(m) + APPEND(s) + return b; +} + +ssize_t +blhexdump(char *buf, size_t len, const char *str, const void *b, size_t l) +{ + size_t z, cz; + int r; + const unsigned char *p = b; + const unsigned char *e = p + l; + + r = snprintf(buf, len, "%s: ", str); + if (r == -1) + return -1; + if ((cz = z = (size_t)r) >= len) + cz = len; + + while (p < e) { + r = snprintf(buf + cz, len - cz, "%.2x", *p++); + if (r == -1) + return -1; + if ((cz = (z += (size_t)r)) >= len) + cz = len; + } + return (ssize_t)z; +} diff --git a/contrib/blacklist/bin/support.h b/contrib/blacklist/bin/support.h new file mode 100644 index 0000000..899649c --- /dev/null +++ b/contrib/blacklist/bin/support.h @@ -0,0 +1,44 @@ +/* $NetBSD: support.h,v 1.7 2016/04/04 15:52:56 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifndef _SUPPORT_H +#define _SUPPORT_H + +__BEGIN_DECLS +const char *fmttime(char *, size_t, time_t); +const char *fmtydhms(char *, size_t, time_t); +void vdlog(int, const char *, va_list) + __attribute__((__format__(__printf__, 2, 0))); +void dlog(int, const char *, ...) + __attribute__((__format__(__printf__, 2, 3))); +ssize_t blhexdump(char *, size_t, const char *, const void *, size_t); +__END_DECLS + +#endif /* _SUPPORT_H */ diff --git a/contrib/blacklist/diff/ftpd.diff b/contrib/blacklist/diff/ftpd.diff new file mode 100644 index 0000000..d28577f --- /dev/null +++ b/contrib/blacklist/diff/ftpd.diff @@ -0,0 +1,91 @@ +--- /dev/null 2015-01-23 17:30:40.000000000 -0500 ++++ pfilter.c 2015-01-23 17:12:02.000000000 -0500 +@@ -0,0 +1,24 @@ ++#include <stdio.h> ++#include <blacklist.h> ++ ++#include "pfilter.h" ++ ++static struct blacklist *blstate; ++ ++void ++pfilter_open(void) ++{ ++ if (blstate == NULL) ++ blstate = blacklist_open(); ++} ++ ++void ++pfilter_notify(int what, const char *msg) ++{ ++ pfilter_open(); ++ ++ if (blstate == NULL) ++ return; ++ ++ blacklist_r(blstate, what, 0, msg); ++} +--- /dev/null 2015-01-23 17:30:40.000000000 -0500 ++++ pfilter.h 2015-01-23 17:07:25.000000000 -0500 +@@ -0,0 +1,2 @@ ++void pfilter_open(void); ++void pfilter_notify(int, const char *); +Index: Makefile +=================================================================== +RCS file: /cvsroot/src/libexec/ftpd/Makefile,v +retrieving revision 1.63 +diff -u -p -u -r1.63 Makefile +--- Makefile 14 Aug 2011 11:46:28 -0000 1.63 ++++ Makefile 23 Jan 2015 22:32:20 -0000 +@@ -11,6 +11,10 @@ LDADD+= -lcrypt -lutil + MAN= ftpd.conf.5 ftpusers.5 ftpd.8 + MLINKS= ftpusers.5 ftpchroot.5 + ++SRCS+= pfilter.c ++LDADD+= -lblacklist ++DPADD+= ${LIBBLACKLIST} ++ + .if defined(NO_INTERNAL_LS) + CPPFLAGS+=-DNO_INTERNAL_LS + .else +Index: ftpd.c +=================================================================== +RCS file: /cvsroot/src/libexec/ftpd/ftpd.c,v +retrieving revision 1.200 +diff -u -p -u -r1.200 ftpd.c +--- ftpd.c 31 Jul 2013 19:50:47 -0000 1.200 ++++ ftpd.c 23 Jan 2015 22:32:20 -0000 +@@ -165,6 +165,8 @@ __RCSID("$NetBSD: ftpd.c,v 1.200 2013/07 + #include <security/pam_appl.h> + #endif + ++#include "pfilter.h" ++ + #define GLOBAL + #include "extern.h" + #include "pathnames.h" +@@ -471,6 +473,8 @@ main(int argc, char *argv[]) + if (EMPTYSTR(confdir)) + confdir = _DEFAULT_CONFDIR; + ++ pfilter_open(); ++ + if (dowtmp) { + #ifdef SUPPORT_UTMPX + ftpd_initwtmpx(); +@@ -1401,6 +1405,7 @@ do_pass(int pass_checked, int pass_rval, + if (rval) { + reply(530, "%s", rval == 2 ? "Password expired." : + "Login incorrect."); ++ pfilter_notify(1, rval == 2 ? "exppass" : "badpass"); + if (logging) { + syslog(LOG_NOTICE, + "FTP LOGIN FAILED FROM %s", remoteloghost); +@@ -1444,6 +1449,7 @@ do_pass(int pass_checked, int pass_rval, + *remote_ip = 0; + remote_ip[sizeof(remote_ip) - 1] = 0; + if (!auth_hostok(lc, remotehost, remote_ip)) { ++ pfilter_notify(1, "bannedhost"); + syslog(LOG_INFO|LOG_AUTH, + "FTP LOGIN FAILED (HOST) as %s: permission denied.", + pw->pw_name); diff --git a/contrib/blacklist/diff/named.diff b/contrib/blacklist/diff/named.diff new file mode 100644 index 0000000..fcd97ba --- /dev/null +++ b/contrib/blacklist/diff/named.diff @@ -0,0 +1,216 @@ +--- /dev/null 2015-01-22 01:48:00.000000000 -0500 ++++ dist/bin/named/pfilter.c 2015-01-22 01:35:16.000000000 -0500 +@@ -0,0 +1,42 @@ ++#include <config.h> ++ ++#include <isc/platform.h> ++#include <isc/util.h> ++#include <named/types.h> ++#include <named/client.h> ++ ++#include <blacklist.h> ++ ++#include "pfilter.h" ++ ++static struct blacklist *blstate; ++ ++void ++pfilter_open(void) ++{ ++ if (blstate == NULL) ++ blstate = blacklist_open(); ++} ++ ++#define TCP_CLIENT(c) (((c)->attributes & NS_CLIENTATTR_TCP) != 0) ++ ++void ++pfilter_notify(isc_result_t res, ns_client_t *client, const char *msg) ++{ ++ isc_socket_t *socket; ++ ++ pfilter_open(); ++ ++ if (TCP_CLIENT(client)) ++ socket = client->tcpsocket; ++ else { ++ socket = client->udpsocket; ++ if (!client->peeraddr_valid) ++ return; ++ } ++ if (socket == NULL) ++ return; ++ blacklist_sa_r(blstate, ++ res != ISC_R_SUCCESS, isc_socket_getfd(socket), ++ &client->peeraddr.type.sa, client->peeraddr.length, msg); ++} +--- /dev/null 2015-01-22 01:48:00.000000000 -0500 ++++ dist/bin/named/pfilter.h 2015-01-22 01:16:56.000000000 -0500 +@@ -0,0 +1,2 @@ ++void pfilter_open(void); ++void pfilter_notify(isc_result_t, ns_client_t *, const char *); +Index: bin/named/Makefile +=================================================================== +RCS file: /cvsroot/src/external/bsd/bind/bin/named/Makefile,v +retrieving revision 1.8 +diff -u -u -r1.8 Makefile +--- bin/named/Makefile 31 Dec 2013 20:23:12 -0000 1.8 ++++ bin/named/Makefile 23 Jan 2015 21:37:09 -0000 +@@ -33,7 +33,9 @@ + lwaddr.c lwdclient.c lwderror.c \ + lwdgabn.c lwdgnba.c lwdgrbn.c lwdnoop.c lwresd.c lwsearch.c \ + main.c notify.c query.c server.c sortlist.c statschannel.c \ +- tkeyconf.c tsigconf.c \ ++ pfilter.c tkeyconf.c tsigconf.c \ + update.c xfrout.c zoneconf.c ${SRCS_UNIX} + ++LDADD+=-lblacklist ++DPADD+=${LIBBLACKLIST} + .include <bsd.prog.mk> +Index: dist/bin/named/client.c +=================================================================== +RCS file: /cvsroot/src/external/bsd/bind/dist/bin/named/client.c,v +retrieving revision 1.11 +diff -u -u -r1.11 client.c +--- dist/bin/named/client.c 10 Dec 2014 04:37:51 -0000 1.11 ++++ dist/bin/named/client.c 23 Jan 2015 21:37:09 -0000 +@@ -65,6 +65,8 @@ + #include <named/server.h> + #include <named/update.h> + ++#include "pfilter.h" ++ + /*** + *** Client + ***/ +@@ -3101,6 +3103,7 @@ + result = ns_client_checkaclsilent(client, sockaddr ? &netaddr : NULL, + acl, default_allow); + ++ pfilter_notify(result, client, opname); + if (result == ISC_R_SUCCESS) + ns_client_log(client, DNS_LOGCATEGORY_SECURITY, + NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3), +Index: dist/bin/named/main.c +=================================================================== +RCS file: /cvsroot/src/external/bsd/bind/dist/bin/named/main.c,v +retrieving revision 1.15 +diff -u -u -r1.15 main.c +--- dist/bin/named/main.c 10 Dec 2014 04:37:51 -0000 1.15 ++++ dist/bin/named/main.c 23 Jan 2015 21:37:09 -0000 +@@ -83,6 +83,9 @@ + #ifdef HAVE_LIBXML2 + #include <libxml/xmlversion.h> + #endif ++ ++#include "pfilter.h" ++ + /* + * Include header files for database drivers here. + */ +@@ -1206,6 +1209,8 @@ + + parse_command_line(argc, argv); + ++ pfilter_open(); ++ + /* + * Warn about common configuration error. + */ +Index: dist/bin/named/query.c +=================================================================== +RCS file: /cvsroot/src/external/bsd/bind/dist/bin/named/query.c,v +retrieving revision 1.17 +diff -u -u -r1.17 query.c +--- dist/bin/named/query.c 10 Dec 2014 04:37:52 -0000 1.17 ++++ dist/bin/named/query.c 23 Jan 2015 21:37:09 -0000 +@@ -65,6 +65,8 @@ + #include <named/sortlist.h> + #include <named/xfrout.h> + ++#include "pfilter.h" ++ + #if 0 + /* + * It has been recommended that DNS64 be changed to return excluded +@@ -762,6 +764,8 @@ + } + + result = ns_client_checkaclsilent(client, NULL, queryacl, ISC_TRUE); ++ if (result != ISC_R_SUCCESS) ++ pfilter_notify(result, client, "validatezonedb"); + if ((options & DNS_GETDB_NOLOG) == 0) { + char msg[NS_CLIENT_ACLMSGSIZE("query")]; + if (result == ISC_R_SUCCESS) { +@@ -1026,6 +1030,8 @@ + result = ns_client_checkaclsilent(client, NULL, + client->view->cacheacl, + ISC_TRUE); ++ if (result == ISC_R_SUCCESS) ++ pfilter_notify(result, client, "cachedb"); + if (result == ISC_R_SUCCESS) { + /* + * We were allowed by the "allow-query-cache" ACL. +Index: dist/bin/named/update.c +=================================================================== +RCS file: /cvsroot/src/external/bsd/bind/dist/bin/named/update.c,v +retrieving revision 1.9 +diff -u -u -r1.9 update.c +--- dist/bin/named/update.c 10 Dec 2014 04:37:52 -0000 1.9 ++++ dist/bin/named/update.c 23 Jan 2015 21:37:09 -0000 +@@ -59,6 +59,8 @@ + #include <named/server.h> + #include <named/update.h> + ++#include "pfilter.h" ++ + /*! \file + * \brief + * This module implements dynamic update as in RFC2136. +@@ -307,6 +309,7 @@ + + result = ns_client_checkaclsilent(client, NULL, queryacl, ISC_TRUE); + if (result != ISC_R_SUCCESS) { ++ pfilter_notify(result, client, "queryacl"); + dns_name_format(zonename, namebuf, sizeof(namebuf)); + dns_rdataclass_format(client->view->rdclass, classbuf, + sizeof(classbuf)); +@@ -324,6 +327,7 @@ + sizeof(classbuf)); + + result = DNS_R_REFUSED; ++ pfilter_notify(result, client, "updateacl"); + ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, + NS_LOGMODULE_UPDATE, ISC_LOG_INFO, + "update '%s/%s' denied", namebuf, classbuf); +@@ -362,6 +366,7 @@ + msg = "disabled"; + } else { + result = ns_client_checkaclsilent(client, NULL, acl, ISC_FALSE); ++ pfilter_notify(result, client, "updateacl"); + if (result == ISC_R_SUCCESS) { + level = ISC_LOG_DEBUG(3); + msg = "approved"; +Index: dist/bin/named/xfrout.c +=================================================================== +RCS file: /cvsroot/src/external/bsd/bind/dist/bin/named/xfrout.c,v +retrieving revision 1.7 +diff -u -u -r1.7 xfrout.c +--- dist/bin/named/xfrout.c 10 Dec 2014 04:37:52 -0000 1.7 ++++ dist/bin/named/xfrout.c 23 Jan 2015 21:37:09 -0000 +@@ -54,6 +54,8 @@ + #include <named/server.h> + #include <named/xfrout.h> + ++#include "pfilter.h" ++ + /*! \file + * \brief + * Outgoing AXFR and IXFR. +@@ -822,6 +824,7 @@ + &client->peeraddr, + &db); + ++ pfilter_notify(result, client, "zonexfr"); + if (result == ISC_R_NOPERM) { + char _buf1[DNS_NAME_FORMATSIZE]; + char _buf2[DNS_RDATACLASS_FORMATSIZE]; diff --git a/contrib/blacklist/diff/proftpd.diff b/contrib/blacklist/diff/proftpd.diff new file mode 100644 index 0000000..c811c9c --- /dev/null +++ b/contrib/blacklist/diff/proftpd.diff @@ -0,0 +1,124 @@ +--- Make.rules.in.orig 2015-05-27 20:25:54.000000000 -0400 ++++ Make.rules.in 2016-01-25 21:48:47.000000000 -0500 +@@ -110,3 +110,8 @@ + + FTPWHO_OBJS=ftpwho.o scoreboard.o misc.o + BUILD_FTPWHO_OBJS=utils/ftpwho.o utils/scoreboard.o utils/misc.o ++ ++CPPFLAGS+=-DHAVE_BLACKLIST ++LIBS+=-lblacklist ++OBJS+= pfilter.o ++BUILD_OBJS+= src/pfilter.o +--- /dev/null 2016-01-22 17:30:55.000000000 -0500 ++++ include/pfilter.h 2016-01-22 16:18:33.000000000 -0500 +@@ -0,0 +1,3 @@ ++ ++void pfilter_notify(int); ++void pfilter_init(void); +--- modules/mod_auth.c.orig 2015-05-27 20:25:54.000000000 -0400 ++++ modules/mod_auth.c 2016-01-22 16:21:06.000000000 -0500 +@@ -30,6 +30,7 @@ + + #include "conf.h" + #include "privs.h" ++#include "pfilter.h" + + extern pid_t mpid; + +@@ -84,6 +85,8 @@ + _("Login timeout (%d %s): closing control connection"), TimeoutLogin, + TimeoutLogin != 1 ? "seconds" : "second"); + ++ pfilter_notify(1); ++ + /* It's possible that any listeners of this event might terminate the + * session process themselves (e.g. mod_ban). So write out that the + * TimeoutLogin has been exceeded to the log here, in addition to the +@@ -913,6 +916,7 @@ + pr_memscrub(pass, strlen(pass)); + } + ++ pfilter_notify(1); + pr_log_auth(PR_LOG_NOTICE, "SECURITY VIOLATION: Root login attempted"); + return 0; + } +@@ -1726,6 +1730,7 @@ + return 1; + + auth_failure: ++ pfilter_notify(1); + if (pass) + pr_memscrub(pass, strlen(pass)); + session.user = session.group = NULL; +--- src/main.c.orig 2016-01-22 17:36:43.000000000 -0500 ++++ src/main.c 2016-01-22 17:37:58.000000000 -0500 +@@ -49,6 +49,7 @@ + #endif + + #include "privs.h" ++#include "pfilter.h" + + int (*cmd_auth_chk)(cmd_rec *); + void (*cmd_handler)(server_rec *, conn_t *); +@@ -1050,6 +1051,7 @@ + pid_t pid; + sigset_t sig_set; + ++ pfilter_init(); + if (!nofork) { + + /* A race condition exists on heavily loaded servers where the parent +@@ -1169,7 +1171,8 @@ + + /* Reseed pseudo-randoms */ + srand((unsigned int) (time(NULL) * getpid())); +- ++#else ++ pfilter_init(); + #endif /* PR_DEVEL_NO_FORK */ + + /* Child is running here */ +--- /dev/null 2016-01-22 17:30:55.000000000 -0500 ++++ src/pfilter.c 2016-01-22 16:37:55.000000000 -0500 +@@ -0,0 +1,41 @@ ++#include "pfilter.h" ++#include "conf.h" ++#include "privs.h" ++#ifdef HAVE_BLACKLIST ++#include <blacklist.h> ++#endif ++ ++static struct blacklist *blstate; ++ ++void ++pfilter_init(void) ++{ ++#ifdef HAVE_BLACKLIST ++ if (blstate == NULL) ++ blstate = blacklist_open(); ++#endif ++} ++ ++void ++pfilter_notify(int a) ++{ ++#ifdef HAVE_BLACKLIST ++ conn_t *c = session.c; ++ int fd; ++ ++ if (c == NULL) ++ return; ++ if (c->rfd != -1) ++ fd = c->rfd; ++ else if (c->wfd != -1) ++ fd = c->wfd; ++ else ++ return; ++ ++ if (blstate == NULL) ++ pfilter_init(); ++ if (blstate == NULL) ++ return; ++ (void)blacklist_r(blstate, a, fd, "proftpd"); ++#endif ++} diff --git a/contrib/blacklist/diff/ssh.diff b/contrib/blacklist/diff/ssh.diff new file mode 100644 index 0000000..bc0b75c --- /dev/null +++ b/contrib/blacklist/diff/ssh.diff @@ -0,0 +1,231 @@ +--- /dev/null 2015-01-22 23:10:33.000000000 -0500 ++++ dist/pfilter.c 2015-01-22 23:46:03.000000000 -0500 +@@ -0,0 +1,28 @@ ++#include "namespace.h" ++#include "includes.h" ++#include "ssh.h" ++#include "packet.h" ++#include "log.h" ++#include "pfilter.h" ++#include <blacklist.h> ++ ++static struct blacklist *blstate; ++ ++void ++pfilter_init(void) ++{ ++ blstate = blacklist_open(); ++} ++ ++void ++pfilter_notify(int a) ++{ ++ int fd; ++ if (blstate == NULL) ++ pfilter_init(); ++ if (blstate == NULL) ++ return; ++ // XXX: 3? ++ fd = packet_connection_is_on_socket() ? packet_get_connection_in() : 3; ++ (void)blacklist_r(blstate, a, fd, "ssh"); ++} +--- /dev/null 2015-01-20 21:14:44.000000000 -0500 ++++ dist/pfilter.h 2015-01-20 20:16:20.000000000 -0500 +@@ -0,0 +1,3 @@ ++ ++void pfilter_notify(int); ++void pfilter_init(void); +Index: bin/sshd/Makefile +=================================================================== +RCS file: /cvsroot/src/crypto/external/bsd/openssh/bin/sshd/Makefile,v +retrieving revision 1.10 +diff -u -u -r1.10 Makefile +--- bin/sshd/Makefile 19 Oct 2014 16:30:58 -0000 1.10 ++++ bin/sshd/Makefile 22 Jan 2015 21:39:21 -0000 +@@ -15,7 +15,7 @@ + auth2-none.c auth2-passwd.c auth2-pubkey.c \ + monitor_mm.c monitor.c monitor_wrap.c \ + kexdhs.c kexgexs.c kexecdhs.c sftp-server.c sftp-common.c \ +- roaming_common.c roaming_serv.c sandbox-rlimit.c ++ roaming_common.c roaming_serv.c sandbox-rlimit.c pfilter.c + + COPTS.auth-options.c= -Wno-pointer-sign + COPTS.ldapauth.c= -Wno-format-nonliteral # XXX: should fix +@@ -68,3 +68,6 @@ + + LDADD+= -lwrap + DPADD+= ${LIBWRAP} ++ ++LDADD+= -lblacklist ++DPADD+= ${LIBBLACKLIST} +Index: dist/auth.c +=================================================================== +RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/auth.c,v +retrieving revision 1.10 +diff -u -u -r1.10 auth.c +--- dist/auth.c 19 Oct 2014 16:30:58 -0000 1.10 ++++ dist/auth.c 22 Jan 2015 21:39:22 -0000 +@@ -62,6 +62,7 @@ + #include "monitor_wrap.h" + #include "krl.h" + #include "compat.h" ++#include "pfilter.h" + + #ifdef HAVE_LOGIN_CAP + #include <login_cap.h> +@@ -362,6 +363,8 @@ + compat20 ? "ssh2" : "ssh1", + authctxt->info != NULL ? ": " : "", + authctxt->info != NULL ? authctxt->info : ""); ++ if (!authctxt->postponed) ++ pfilter_notify(!authenticated); + free(authctxt->info); + authctxt->info = NULL; + } +Index: dist/sshd.c +=================================================================== +RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/sshd.c,v +retrieving revision 1.15 +diff -u -u -r1.15 sshd.c +--- dist/sshd.c 28 Oct 2014 21:36:16 -0000 1.15 ++++ dist/sshd.c 22 Jan 2015 21:39:22 -0000 +@@ -109,6 +109,7 @@ + #include "roaming.h" + #include "ssh-sandbox.h" + #include "version.h" ++#include "pfilter.h" + + #ifdef LIBWRAP + #include <tcpd.h> +@@ -364,6 +365,7 @@ + killpg(0, SIGTERM); + } + ++ pfilter_notify(1); + /* Log error and exit. */ + sigdie("Timeout before authentication for %s", get_remote_ipaddr()); + } +@@ -1160,6 +1162,7 @@ + for (i = 0; i < options.max_startups; i++) + startup_pipes[i] = -1; + ++ pfilter_init(); + /* + * Stay listening for connections until the system crashes or + * the daemon is killed with a signal. +Index: auth1.c +=================================================================== +RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/auth1.c,v +retrieving revision 1.9 +diff -u -u -r1.9 auth1.c +--- auth1.c 19 Oct 2014 16:30:58 -0000 1.9 ++++ auth1.c 14 Feb 2015 15:40:51 -0000 +@@ -41,6 +41,7 @@ + #endif + #include "monitor_wrap.h" + #include "buffer.h" ++#include "pfilter.h" + + /* import */ + extern ServerOptions options; +@@ -445,6 +446,7 @@ + else { + debug("do_authentication: invalid user %s", user); + authctxt->pw = fakepw(); ++ pfilter_notify(1); + } + + /* Configuration may have changed as a result of Match */ +Index: auth2.c +=================================================================== +RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/auth2.c,v +retrieving revision 1.9 +diff -u -u -r1.9 auth2.c +--- auth2.c 19 Oct 2014 16:30:58 -0000 1.9 ++++ auth2.c 14 Feb 2015 15:40:51 -0000 +@@ -52,6 +52,7 @@ + #include "pathnames.h" + #include "buffer.h" + #include "canohost.h" ++#include "pfilter.h" + + #ifdef GSSAPI + #include "ssh-gss.h" +@@ -256,6 +257,7 @@ + } else { + logit("input_userauth_request: invalid user %s", user); + authctxt->pw = fakepw(); ++ pfilter_notify(1); + } + #ifdef USE_PAM + if (options.use_pam) +Index: sshd.c +=================================================================== +RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/sshd.c,v +retrieving revision 1.16 +diff -u -r1.16 sshd.c +--- sshd.c 25 Jan 2015 15:52:44 -0000 1.16 ++++ sshd.c 14 Feb 2015 09:55:06 -0000 +@@ -628,6 +628,8 @@ + explicit_bzero(pw->pw_passwd, strlen(pw->pw_passwd)); + endpwent(); + ++ pfilter_init(); ++ + /* Change our root directory */ + if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) + fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, + +Index: auth-pam.c +=================================================================== +RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/auth-pam.c,v +retrieving revision 1.7 +diff -u -u -r1.7 auth-pam.c +--- auth-pam.c 3 Jul 2015 00:59:59 -0000 1.7 ++++ auth-pam.c 23 Jan 2016 00:01:16 -0000 +@@ -114,6 +114,7 @@ + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" ++#include "pfilter.h" + + extern ServerOptions options; + extern Buffer loginmsg; +@@ -809,6 +810,7 @@ + free(msg); + return (0); + } ++ pfilter_notify(1); + error("PAM: %s for %s%.100s from %.100s", msg, + sshpam_authctxt->valid ? "" : "illegal user ", + sshpam_authctxt->user, +Index: auth.c +=================================================================== +RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/auth.c,v +retrieving revision 1.15 +diff -u -u -r1.15 auth.c +--- auth.c 21 Aug 2015 08:20:59 -0000 1.15 ++++ auth.c 23 Jan 2016 00:01:16 -0000 +@@ -656,6 +656,7 @@ + + pw = getpwnam(user); + if (pw == NULL) { ++ pfilter_notify(1); + logit("Invalid user %.100s from %.100s", + user, get_remote_ipaddr()); + return (NULL); +Index: auth1.c +=================================================================== +RCS file: /cvsroot/src/crypto/external/bsd/openssh/dist/auth1.c,v +retrieving revision 1.12 +diff -u -u -r1.12 auth1.c +--- auth1.c 3 Jul 2015 00:59:59 -0000 1.12 ++++ auth1.c 23 Jan 2016 00:01:16 -0000 +@@ -376,6 +376,7 @@ + char *msg; + size_t len; + ++ pfilter_notify(1); + error("Access denied for user %s by PAM account " + "configuration", authctxt->user); + len = buffer_len(&loginmsg); diff --git a/contrib/blacklist/etc/Makefile b/contrib/blacklist/etc/Makefile new file mode 100644 index 0000000..669528d --- /dev/null +++ b/contrib/blacklist/etc/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.3 2015/01/26 00:18:40 christos Exp $ + +SUBDIR=rc.d + +FILESDIR= /usr/share/examples/blacklist +FILESMODE= 644 +FILES= blacklistd.conf npf.conf + +.include <bsd.files.mk> +.include <bsd.subdir.mk> diff --git a/contrib/blacklist/etc/blacklistd.conf b/contrib/blacklist/etc/blacklistd.conf new file mode 100644 index 0000000..f061b00 --- /dev/null +++ b/contrib/blacklist/etc/blacklistd.conf @@ -0,0 +1,14 @@ +# Blacklist rule +# adr/mask:port type proto owner name nfail disable +[local] +ssh stream * * * 3 6h +ftp stream * * * 3 6h +domain * * named * 3 12h +#6161 stream tcp6 christos * 2 10m +* * * * * 3 60 + +# adr/mask:port type proto owner name nfail disable +[remote] +#129.168.0.0/16 * * * = * * +#6161 = = = =/24 = = +#* stream tcp * = = = diff --git a/contrib/blacklist/etc/npf.conf b/contrib/blacklist/etc/npf.conf new file mode 100644 index 0000000..42d5604 --- /dev/null +++ b/contrib/blacklist/etc/npf.conf @@ -0,0 +1,15 @@ +# Transparent firewall example for blacklistd + +$ext_if = "bnx0" + +set bpf.jit on; +alg "icmp" + +group "external" on $ext_if { + ruleset "blacklistd" + pass final all +} + +group default { + pass final all +} diff --git a/contrib/blacklist/etc/rc.d/Makefile b/contrib/blacklist/etc/rc.d/Makefile new file mode 100644 index 0000000..e863d08 --- /dev/null +++ b/contrib/blacklist/etc/rc.d/Makefile @@ -0,0 +1,6 @@ +# $NetBSD: Makefile,v 1.1 2015/01/22 17:49:41 christos Exp $ + +SCRIPTS=blacklistd +SCRIPTSDIR=/etc/rc.d + +.include <bsd.prog.mk> diff --git a/contrib/blacklist/etc/rc.d/blacklistd b/contrib/blacklist/etc/rc.d/blacklistd new file mode 100644 index 0000000..2e46f51 --- /dev/null +++ b/contrib/blacklist/etc/rc.d/blacklistd @@ -0,0 +1,57 @@ +#!/bin/sh +# +# $NetBSD: blacklistd,v 1.1 2015/01/22 17:49:41 christos Exp $ +# + +# PROVIDE: blacklistd +# REQUIRE: npf +# BEFORE: SERVERS + +$_rc_subr_loaded . /etc/rc.subr + +name="blacklistd" +rcvar=$name +command="/sbin/${name}" +pidfile="/var/run/${name}.pid" +required_files="/etc/${name}.conf" +start_precmd="${name}_precmd" +extra_commands="reload" + +_sockfile="/var/run/${name}.sockets" +_sockname="blsock" + +blacklistd_precmd() +{ + # Create default list of blacklistd sockets to watch + # + ( umask 022 ; > $_sockfile ) + + # Find /etc/rc.d scripts with "chrootdir" rcorder(8) keyword, + # and if $${app}_chrootdir is a directory, add appropriate + # blacklistd socket to list of sockets to watch. + # + for _lr in $(rcorder -k chrootdir /etc/rc.d/*); do + ( + _l=${_lr##*/} + load_rc_config ${_l} + eval _ldir=\$${_l}_chrootdir + if checkyesno $_l && [ -n "$_ldir" ]; then + echo "${_ldir}/var/run/${_sockname}" >> $_sockfile + fi + ) + done + + # If other sockets have been provided, change run_rc_command()'s + # internal copy of $blacklistd_flags to force use of specific + # blacklistd sockets. + # + if [ -s $_sockfile ]; then + echo "/var/run/${_sockname}" >> $_sockfile + rc_flags="-P $_sockfile $rc_flags" + fi + + return 0 +} + +load_rc_config $name +run_rc_command "$1" diff --git a/contrib/blacklist/include/Makefile b/contrib/blacklist/include/Makefile new file mode 100644 index 0000000..6854907 --- /dev/null +++ b/contrib/blacklist/include/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.1 2015/01/21 16:16:00 christos Exp $ + +# Doing a make includes builds /usr/include + +NOOBJ= # defined + +INCS= blacklist.h +INCSDIR= /usr/include + +.include <bsd.prog.mk> diff --git a/contrib/blacklist/include/bl.h b/contrib/blacklist/include/bl.h new file mode 100644 index 0000000..68249cd --- /dev/null +++ b/contrib/blacklist/include/bl.h @@ -0,0 +1,76 @@ +/* $NetBSD: bl.h,v 1.13 2016/03/11 17:16:40 christos Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifndef _BL_H +#define _BL_H + +#include <stdbool.h> +#include <stdarg.h> +#include <sys/param.h> +#include <sys/socket.h> +#include "blacklist.h" + +typedef enum { + BL_INVALID, + BL_ADD, + BL_DELETE +} bl_type_t; + +typedef struct { + bl_type_t bi_type; + int bi_fd; + uid_t bi_uid; + gid_t bi_gid; + socklen_t bi_slen; + struct sockaddr_storage bi_ss; + char bi_msg[1024]; +} bl_info_t; + +#define bi_cred bi_u._bi_cred + +#ifndef _PATH_BLSOCK +#define _PATH_BLSOCK "/var/run/blacklistd.sock" +#endif + +__BEGIN_DECLS + +typedef struct blacklist *bl_t; + +bl_t bl_create(bool, const char *, void (*)(int, const char *, va_list)); +void bl_destroy(bl_t); +int bl_send(bl_t, bl_type_t, int, const struct sockaddr *, socklen_t, + const char *); +int bl_getfd(bl_t); +bl_info_t *bl_recv(bl_t); +bool bl_isconnected(bl_t); + +__END_DECLS + +#endif /* _BL_H */ diff --git a/contrib/blacklist/include/blacklist.h b/contrib/blacklist/include/blacklist.h new file mode 100644 index 0000000..9ebe11b --- /dev/null +++ b/contrib/blacklist/include/blacklist.h @@ -0,0 +1,46 @@ +/* $NetBSD: blacklist.h,v 1.3 2015/01/23 18:48:56 christos Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifndef _BLACKLIST_H +#define _BLACKLIST_H + +#include <sys/socket.h> + +__BEGIN_DECLS +struct blacklist *blacklist_open(void); +void blacklist_close(struct blacklist *); +int blacklist(int, int, const char *); +int blacklist_r(struct blacklist *, int, int, const char *); +int blacklist_sa(int, int, const struct sockaddr *, socklen_t, const char *); +int blacklist_sa_r(struct blacklist *, int, int, + const struct sockaddr *, socklen_t, const char *); +__END_DECLS + +#endif /* _BLACKLIST_H */ diff --git a/contrib/blacklist/lib/Makefile b/contrib/blacklist/lib/Makefile new file mode 100644 index 0000000..aea01ca --- /dev/null +++ b/contrib/blacklist/lib/Makefile @@ -0,0 +1,19 @@ +# $NetBSD: Makefile,v 1.6 2016/01/05 13:07:46 christos Exp $ + +.include <bsd.own.mk> + +USE_SHLIBDIR= yes + +CPPFLAGS+=-D_REENTRANT +LIBDPLIBS+=pthread ${NETBSDSRCDIR}/lib/libpthread +LIB=blacklist +SRCS=bl.c blacklist.c +MAN=libblacklist.3 +MLINKS+=libblacklist.3 blacklist_open.3 +MLINKS+=libblacklist.3 blacklist_close.3 +MLINKS+=libblacklist.3 blacklist.3 +MLINKS+=libblacklist.3 blacklist_r.3 +MLINKS+=libblacklist.3 blacklist_sa.3 +MLINKS+=libblacklist.3 blacklist_sa_r.3 + +.include <bsd.lib.mk> diff --git a/contrib/blacklist/lib/bl.c b/contrib/blacklist/lib/bl.c new file mode 100644 index 0000000..bca52cf --- /dev/null +++ b/contrib/blacklist/lib/bl.c @@ -0,0 +1,524 @@ +/* $NetBSD: bl.c,v 1.27 2015/12/30 16:42:48 christos Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: bl.c,v 1.27 2015/12/30 16:42:48 christos Exp $"); + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> + +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <signal.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdint.h> +#include <stdbool.h> +#include <errno.h> +#include <stdarg.h> +#include <netinet/in.h> +#ifdef _REENTRANT +#include <pthread.h> +#endif + +#include "bl.h" + +typedef struct { + uint32_t bl_len; + uint32_t bl_version; + uint32_t bl_type; + uint32_t bl_salen; + struct sockaddr_storage bl_ss; + char bl_data[]; +} bl_message_t; + +struct blacklist { +#ifdef _REENTRANT + pthread_mutex_t b_mutex; +# define BL_INIT(b) pthread_mutex_init(&b->b_mutex, NULL) +# define BL_LOCK(b) pthread_mutex_lock(&b->b_mutex) +# define BL_UNLOCK(b) pthread_mutex_unlock(&b->b_mutex) +#else +# define BL_INIT(b) do {} while(/*CONSTCOND*/0) +# define BL_LOCK(b) BL_INIT(b) +# define BL_UNLOCK(b) BL_INIT(b) +#endif + int b_fd; + int b_connected; + struct sockaddr_un b_sun; + void (*b_fun)(int, const char *, va_list); + bl_info_t b_info; +}; + +#define BL_VERSION 1 + +bool +bl_isconnected(bl_t b) +{ + return b->b_connected == 0; +} + +int +bl_getfd(bl_t b) +{ + return b->b_fd; +} + +static void +bl_reset(bl_t b, bool locked) +{ + int serrno = errno; + if (!locked) + BL_LOCK(b); + close(b->b_fd); + errno = serrno; + b->b_fd = -1; + b->b_connected = -1; + if (!locked) + BL_UNLOCK(b); +} + +static void +bl_log(void (*fun)(int, const char *, va_list), int level, + const char *fmt, ...) +{ + va_list ap; + int serrno = errno; + + va_start(ap, fmt); + (*fun)(level, fmt, ap); + va_end(ap); + errno = serrno; +} + +static int +bl_init(bl_t b, bool srv) +{ + static int one = 1; + /* AF_UNIX address of local logger */ + mode_t om; + int rv, serrno; + struct sockaddr_un *sun = &b->b_sun; + +#ifndef SOCK_NONBLOCK +#define SOCK_NONBLOCK 0 +#endif +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 0 +#endif +#ifndef SOCK_NOSIGPIPE +#define SOCK_NOSIGPIPE 0 +#endif + + BL_LOCK(b); + + if (b->b_fd == -1) { + b->b_fd = socket(PF_LOCAL, + SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK|SOCK_NOSIGPIPE, 0); + if (b->b_fd == -1) { + bl_log(b->b_fun, LOG_ERR, "%s: socket failed (%m)", + __func__); + BL_UNLOCK(b); + return -1; + } +#if SOCK_CLOEXEC == 0 + fcntl(b->b_fd, F_SETFD, FD_CLOEXEC); +#endif +#if SOCK_NONBLOCK == 0 + fcntl(b->b_fd, F_SETFL, fcntl(b->b_fd, F_GETFL) | O_NONBLOCK); +#endif +#if SOCK_NOSIGPIPE == 0 +#ifdef SO_NOSIGPIPE + int o = 1; + setsockopt(b->b_fd, SOL_SOCKET, SO_NOSIGPIPE, &o, sizeof(o)); +#else + signal(SIGPIPE, SIG_IGN); +#endif +#endif + } + + if (bl_isconnected(b)) { + BL_UNLOCK(b); + return 0; + } + + /* + * We try to connect anyway even when we are a server to verify + * that no other server is listening to the socket. If we succeed + * to connect and we are a server, someone else owns it. + */ + rv = connect(b->b_fd, (const void *)sun, (socklen_t)sizeof(*sun)); + if (rv == 0) { + if (srv) { + bl_log(b->b_fun, LOG_ERR, + "%s: another daemon is handling `%s'", + __func__, sun->sun_path); + goto out; + } + } else { + if (!srv) { + /* + * If the daemon is not running, we just try a + * connect, so leave the socket alone until it does + * and only log once. + */ + if (b->b_connected != 1) { + bl_log(b->b_fun, LOG_DEBUG, + "%s: connect failed for `%s' (%m)", + __func__, sun->sun_path); + b->b_connected = 1; + } + BL_UNLOCK(b); + return -1; + } + bl_log(b->b_fun, LOG_DEBUG, "Connected to blacklist server", + __func__); + } + + if (srv) { + (void)unlink(sun->sun_path); + om = umask(0); + rv = bind(b->b_fd, (const void *)sun, (socklen_t)sizeof(*sun)); + serrno = errno; + (void)umask(om); + errno = serrno; + if (rv == -1) { + bl_log(b->b_fun, LOG_ERR, + "%s: bind failed for `%s' (%m)", + __func__, sun->sun_path); + goto out; + } + } + + b->b_connected = 0; +#define GOT_FD 1 +#if defined(LOCAL_CREDS) +#define CRED_LEVEL 0 +#define CRED_NAME LOCAL_CREDS +#define CRED_SC_UID sc_euid +#define CRED_SC_GID sc_egid +#define CRED_MESSAGE SCM_CREDS +#define CRED_SIZE SOCKCREDSIZE(NGROUPS_MAX) +#define CRED_TYPE struct sockcred +#define GOT_CRED 2 +#elif defined(SO_PASSCRED) +#define CRED_LEVEL SOL_SOCKET +#define CRED_NAME SO_PASSCRED +#define CRED_SC_UID uid +#define CRED_SC_GID gid +#define CRED_MESSAGE SCM_CREDENTIALS +#define CRED_SIZE sizeof(struct ucred) +#define CRED_TYPE struct ucred +#define GOT_CRED 2 +#else +#define GOT_CRED 0 +/* + * getpeereid() and LOCAL_PEERCRED don't help here + * because we are not a stream socket! + */ +#define CRED_SIZE 0 +#define CRED_TYPE void * __unused +#endif + +#ifdef CRED_LEVEL + if (setsockopt(b->b_fd, CRED_LEVEL, CRED_NAME, + &one, (socklen_t)sizeof(one)) == -1) { + bl_log(b->b_fun, LOG_ERR, "%s: setsockopt %s " + "failed (%m)", __func__, __STRING(CRED_NAME)); + goto out; + } +#endif + + BL_UNLOCK(b); + return 0; +out: + bl_reset(b, true); + BL_UNLOCK(b); + return -1; +} + +bl_t +bl_create(bool srv, const char *path, void (*fun)(int, const char *, va_list)) +{ + bl_t b = calloc(1, sizeof(*b)); + if (b == NULL) + goto out; + b->b_fun = fun == NULL ? vsyslog : fun; + b->b_fd = -1; + b->b_connected = -1; + BL_INIT(b); + + memset(&b->b_sun, 0, sizeof(b->b_sun)); + b->b_sun.sun_family = AF_LOCAL; +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + b->b_sun.sun_len = sizeof(b->b_sun); +#endif + strlcpy(b->b_sun.sun_path, + path ? path : _PATH_BLSOCK, sizeof(b->b_sun.sun_path)); + + bl_init(b, srv); + return b; +out: + free(b); + bl_log(fun, LOG_ERR, "%s: malloc failed (%m)", __func__); + return NULL; +} + +void +bl_destroy(bl_t b) +{ + bl_reset(b, false); + free(b); +} + +static int +bl_getsock(bl_t b, struct sockaddr_storage *ss, const struct sockaddr *sa, + socklen_t slen, const char *ctx) +{ + uint8_t family; + + memset(ss, 0, sizeof(*ss)); + + switch (slen) { + case 0: + return 0; + case sizeof(struct sockaddr_in): + family = AF_INET; + break; + case sizeof(struct sockaddr_in6): + family = AF_INET6; + break; + default: + bl_log(b->b_fun, LOG_ERR, "%s: invalid socket len %u (%s)", + __func__, (unsigned)slen, ctx); + errno = EINVAL; + return -1; + } + + memcpy(ss, sa, slen); + + if (ss->ss_family != family) { + bl_log(b->b_fun, LOG_INFO, + "%s: correcting socket family %d to %d (%s)", + __func__, ss->ss_family, family, ctx); + ss->ss_family = family; + } + +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + if (ss->ss_len != slen) { + bl_log(b->b_fun, LOG_INFO, + "%s: correcting socket len %u to %u (%s)", + __func__, ss->ss_len, (unsigned)slen, ctx); + ss->ss_len = (uint8_t)slen; + } +#endif + return 0; +} + +int +bl_send(bl_t b, bl_type_t e, int pfd, const struct sockaddr *sa, + socklen_t slen, const char *ctx) +{ + struct msghdr msg; + struct iovec iov; + union { + char ctrl[CMSG_SPACE(sizeof(int))]; + uint32_t fd; + } ua; + struct cmsghdr *cmsg; + union { + bl_message_t bl; + char buf[512]; + } ub; + size_t ctxlen, tried; +#define NTRIES 5 + + ctxlen = strlen(ctx); + if (ctxlen > 128) + ctxlen = 128; + + iov.iov_base = ub.buf; + iov.iov_len = sizeof(bl_message_t) + ctxlen; + ub.bl.bl_len = (uint32_t)iov.iov_len; + ub.bl.bl_version = BL_VERSION; + ub.bl.bl_type = (uint32_t)e; + + if (bl_getsock(b, &ub.bl.bl_ss, sa, slen, ctx) == -1) + return -1; + + + ub.bl.bl_salen = slen; + memcpy(ub.bl.bl_data, ctx, ctxlen); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + + msg.msg_control = ua.ctrl; + msg.msg_controllen = sizeof(ua.ctrl); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + memcpy(CMSG_DATA(cmsg), &pfd, sizeof(pfd)); + + tried = 0; +again: + if (bl_init(b, false) == -1) + return -1; + + if ((sendmsg(b->b_fd, &msg, 0) == -1) && tried++ < NTRIES) { + bl_reset(b, false); + goto again; + } + return tried >= NTRIES ? -1 : 0; +} + +bl_info_t * +bl_recv(bl_t b) +{ + struct msghdr msg; + struct iovec iov; + union { + char ctrl[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(CRED_SIZE)]; + uint32_t fd; + CRED_TYPE sc; + } ua; + struct cmsghdr *cmsg; + CRED_TYPE *sc; + union { + bl_message_t bl; + char buf[512]; + } ub; + int got; + ssize_t rlen; + bl_info_t *bi = &b->b_info; + + got = 0; + memset(bi, 0, sizeof(*bi)); + + iov.iov_base = ub.buf; + iov.iov_len = sizeof(ub); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + + msg.msg_control = ua.ctrl; + msg.msg_controllen = sizeof(ua.ctrl) + 100; + + rlen = recvmsg(b->b_fd, &msg, 0); + if (rlen == -1) { + bl_log(b->b_fun, LOG_ERR, "%s: recvmsg failed (%m)", __func__); + return NULL; + } + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET) { + bl_log(b->b_fun, LOG_ERR, + "%s: unexpected cmsg_level %d", + __func__, cmsg->cmsg_level); + continue; + } + switch (cmsg->cmsg_type) { + case SCM_RIGHTS: + if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) { + bl_log(b->b_fun, LOG_ERR, + "%s: unexpected cmsg_len %d != %zu", + __func__, cmsg->cmsg_len, + CMSG_LEN(2 * sizeof(int))); + continue; + } + memcpy(&bi->bi_fd, CMSG_DATA(cmsg), sizeof(bi->bi_fd)); + got |= GOT_FD; + break; +#ifdef CRED_MESSAGE + case CRED_MESSAGE: + sc = (void *)CMSG_DATA(cmsg); + bi->bi_uid = sc->CRED_SC_UID; + bi->bi_gid = sc->CRED_SC_GID; + got |= GOT_CRED; + break; +#endif + default: + bl_log(b->b_fun, LOG_ERR, + "%s: unexpected cmsg_type %d", + __func__, cmsg->cmsg_type); + continue; + } + + } + + if (got != (GOT_CRED|GOT_FD)) { + bl_log(b->b_fun, LOG_ERR, "message missing %s %s", +#if GOT_CRED != 0 + (got & GOT_CRED) == 0 ? "cred" : +#endif + "", (got & GOT_FD) == 0 ? "fd" : ""); + + return NULL; + } + + if ((size_t)rlen <= sizeof(ub.bl)) { + bl_log(b->b_fun, LOG_ERR, "message too short %zd", rlen); + return NULL; + } + + if (ub.bl.bl_version != BL_VERSION) { + bl_log(b->b_fun, LOG_ERR, "bad version %d", ub.bl.bl_version); + return NULL; + } + + bi->bi_type = ub.bl.bl_type; + bi->bi_slen = ub.bl.bl_salen; + bi->bi_ss = ub.bl.bl_ss; +#ifndef CRED_MESSAGE + bi->bi_uid = -1; + bi->bi_gid = -1; +#endif + strlcpy(bi->bi_msg, ub.bl.bl_data, MIN(sizeof(bi->bi_msg), + ((size_t)rlen - sizeof(ub.bl) + 1))); + return bi; +} diff --git a/contrib/blacklist/lib/blacklist.c b/contrib/blacklist/lib/blacklist.c new file mode 100644 index 0000000..b8a524c --- /dev/null +++ b/contrib/blacklist/lib/blacklist.c @@ -0,0 +1,88 @@ +/* $NetBSD: blacklist.c,v 1.5 2015/01/22 16:19:53 christos Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: blacklist.c,v 1.5 2015/01/22 16:19:53 christos Exp $"); + +#include <stdio.h> +#include <bl.h> + +#include <stdarg.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <syslog.h> + +int +blacklist_sa(int action, int rfd, const struct sockaddr *sa, socklen_t salen, + const char *msg) +{ + struct blacklist *bl; + int rv; + if ((bl = blacklist_open()) == NULL) + return -1; + rv = blacklist_sa_r(bl, action, rfd, sa, salen, msg); + blacklist_close(bl); + return rv; +} + +int +blacklist_sa_r(struct blacklist *bl, int action, int rfd, + const struct sockaddr *sa, socklen_t slen, const char *msg) +{ + return bl_send(bl, action ? BL_ADD : BL_DELETE, rfd, sa, slen, msg); +} + +int +blacklist(int action, int rfd, const char *msg) +{ + return blacklist_sa(action, rfd, NULL, 0, msg); +} + +int +blacklist_r(struct blacklist *bl, int action, int rfd, const char *msg) +{ + return blacklist_sa_r(bl, action, rfd, NULL, 0, msg); +} + +struct blacklist * +blacklist_open(void) { + return bl_create(false, NULL, vsyslog); +} + +void +blacklist_close(struct blacklist *bl) +{ + bl_destroy(bl); +} diff --git a/contrib/blacklist/lib/libblacklist.3 b/contrib/blacklist/lib/libblacklist.3 new file mode 100644 index 0000000..e136820 --- /dev/null +++ b/contrib/blacklist/lib/libblacklist.3 @@ -0,0 +1,125 @@ +.\" $NetBSD: libblacklist.3,v 1.3 2015/01/25 23:09:28 wiz Exp $ +.\" +.\" Copyright (c) 2015 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Christos Zoulas. +.\" +.\" 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. +.\" +.Dd January 22, 2015 +.Dt LIBBLACKLIST 3 +.Os +.Sh NAME +.Nm blacklist_open , +.Nm blacklist_close , +.Nm blacklist_r , +.Nm blacklist , +.Nm blacklist_sa +.Nm blacklist_sa_r , +.Nd Blacklistd notification library +.Sh LIBRARY +.Lb libblacklist +.Sh SYNOPSIS +.In blacklist.h +.Ft struct blacklist * +.Fn blacklist_open "void" +.Ft void +.Fn blacklist_close "struct blacklist *cookie" +.Ft int +.Fn blacklist "int action" "int fd" "const char *msg" +.Ft int +.Fn blacklist_r "struct blacklist *cookie" "int action" "int fd" "const char *msg" +.Ft int +.Fn blacklist_sa "int action" "int fd" "const struct sockaddr *sa" "socklen_t salen" "const char *msg" +.Ft int +.Fn blacklist_sa_r "struct blacklist *cookie" "int action" "int fd" "const struct sockaddr *sa" "socklen_t salen" "const char *msg" +.Sh DESCRIPTION +These functions can be used by daemons to notify +.Xr blacklistd 8 +about successful and failed remote connections so that blacklistd can +block or release port access to prevent Denial of Service attacks. +.Pp +The function +.Fn blacklist_open +creates a the necessary state to communicate with +.Xr blacklistd 8 +and returns a pointer to it, or +.Dv NULL +on failure. +.Pp +The +.Fn blacklist_close +function frees all memory and resources used. +.Pp +The +.Fn blacklist +function sends a message to +.Xr blacklistd 8 , +with an +.Ar action +argument specifying +.Dv 1 +for a failed connection or +.Dv 0 +for a successful connection, +a file descriptor +.Ar fd +specifying the accepted file descriptor connected to the client, +and an optional message in the +.Ar msg +argument. +.Pp +The +.Fn blacklist_r +function is more efficient because it keeps the blacklist state around. +.Pp +The +.Fn blacklist_sa +and +.Fn blacklist_sa_r +functions can be used with unconnected sockets, where +.Xr getpeername 2 +will not work, the server will pass the peer name in the message. +.Pp +All functions log errors to +.Xr syslogd 8 . +.Sh RETURN VALUES +The function +.Fn bl_open +returns a cookie on success and +.Dv NULL +on failure setting errno to an appropriate value. +.Pp +The +.Fn bl_send +function returns +.Dv 0 +on success and +.Dv -1 +on failure setting errno to an appropriate value. +.Sh SEE ALSO +.Xr blacklistd.conf 5 , +.Xr blacklistd 8 +.Sh AUTHORS +.An Christos Zoulas diff --git a/contrib/blacklist/lib/shlib_version b/contrib/blacklist/lib/shlib_version new file mode 100644 index 0000000..97c9f92 --- /dev/null +++ b/contrib/blacklist/lib/shlib_version @@ -0,0 +1,2 @@ +major=0 +minor=0 diff --git a/contrib/blacklist/libexec/Makefile b/contrib/blacklist/libexec/Makefile new file mode 100644 index 0000000..6537080 --- /dev/null +++ b/contrib/blacklist/libexec/Makefile @@ -0,0 +1,6 @@ +# $NetBSD: Makefile,v 1.1 2015/01/22 17:49:41 christos Exp $ + +SCRIPTS= blacklistd-helper +SCRIPTSDIR= /libexec + +.include <bsd.prog.mk> diff --git a/contrib/blacklist/libexec/blacklistd-helper b/contrib/blacklist/libexec/blacklistd-helper new file mode 100644 index 0000000..743ccf5 --- /dev/null +++ b/contrib/blacklist/libexec/blacklistd-helper @@ -0,0 +1,82 @@ +#!/bin/sh +#echo "run $@" 1>&2 +#set -x +# $1 command +# $2 rulename +# $3 protocol +# $4 address +# $5 mask +# $6 port +# $7 id + +pf= +for f in npf pf; do + if [ -f "/etc/$f.conf" ]; then + pf="$f" + break + fi +done + +if [ -z "$pf" ]; then + echo "$0: Unsupported packet filter" 1>&2 + exit 1 +fi + +if [ -n "$3" ]; then + proto="proto $3" +fi + +if [ -n "$6" ]; then + port="port $6" +fi + +addr="$4" +mask="$5" +case "$4" in +::ffff:*.*.*.*) + if [ "$5" = 128 ]; then + mask=32 + addr=${4#::ffff:} + fi;; +esac + +case "$1" in +add) + case "$pf" in + npf) + /sbin/npfctl rule "$2" add block in final $proto from \ + "$addr/$mask" to any $port + ;; + pf) + # insert $ip/$mask into per-protocol anchored table + /sbin/pfctl -a "$2" -t "port$6" -T add "$addr/$mask" + echo "block in quick $proto from <port$6> to any $port" | \ + /sbin/pfctl -a "$2" -f - + ;; + esac + ;; +rem) + case "$pf" in + npf) + /sbin/npfctl rule "$2" rem-id "$7" + ;; + pf) + /sbin/pfctl -a "$2" -t "port$6" -T delete "$addr/$mask" + ;; + esac + ;; +flush) + case "$pf" in + npf) + /sbin/npfctl rule "$2" flush + ;; + pf) + /sbin/pfctl -a "$2" -t "port$6" -T flush + ;; + esac + ;; +*) + echo "$0: Unknown command '$1'" 1>&2 + exit 1 + ;; +esac diff --git a/contrib/blacklist/port/Makefile.am b/contrib/blacklist/port/Makefile.am new file mode 100644 index 0000000..f1b36ca --- /dev/null +++ b/contrib/blacklist/port/Makefile.am @@ -0,0 +1,25 @@ +# +ACLOCAL_AMFLAGS = -I m4 +lib_LTLIBRARIES = libblacklist.la +include_HEADERS = blacklist.h + +bin_PROGRAMS = blacklistd blacklistctl srvtest cltest + +VPATH = ../bin:../lib:../test + +AM_CPPFLAGS = -I../include -DDOT="." +AM_CFLAGS = @WARNINGS@ + +libblacklist_la_SOURCES = bl.c blacklist.c +libblacklist_la_LDFLAGS = -no-undefined -version-info 0:0:0 +libblacklist_la_LIBADD = $(LTLIBOBJS) + +SRCS = internal.c support.c run.c conf.c state.c +blacklistd_SOURCES = blacklistd.c ${SRCS} +blacklistd_LDADD = libblacklist.la +blacklistctl_SOURCES = blacklistctl.c ${SRCS} +blacklistctl_LDADD = libblacklist.la +srvtest_SOURCES = srvtest.c ${SRCS} +srvtest_LDADD = libblacklist.la +cltest_SOURCES = cltest.c ${SRCS} +cltest_LDADD = libblacklist.la diff --git a/contrib/blacklist/port/_strtoi.h b/contrib/blacklist/port/_strtoi.h new file mode 100644 index 0000000..4b2b4e8 --- /dev/null +++ b/contrib/blacklist/port/_strtoi.h @@ -0,0 +1,93 @@ +/* $NetBSD: _strtoi.h,v 1.1 2015/01/22 02:15:59 christos Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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. + * + * Original version ID: + * NetBSD: src/lib/libc/locale/_wcstoul.h,v 1.2 2003/08/07 16:43:03 agc Exp + * + * Created by Kamil Rytarowski, based on ID: + * NetBSD: src/common/lib/libc/stdlib/_strtoul.h,v 1.7 2013/05/17 12:55:56 joerg Exp + */ + +/* + * function template for strtoi and strtou + * + * parameters: + * _FUNCNAME : function name + * __TYPE : return and range limits type + * __WRAPPED : wrapped function, strtoimax or strtoumax + */ + +__TYPE +_FUNCNAME(const char * __restrict nptr, char ** __restrict endptr, int base, + __TYPE lo, __TYPE hi, int * rstatus) +{ + int serrno; + __TYPE im; + char *ep; + int rep; + + /* endptr may be NULL */ + + if (endptr == NULL) + endptr = &ep; + + if (rstatus == NULL) + rstatus = &rep; + + serrno = errno; + errno = 0; + + im = __WRAPPED(nptr, endptr, base); + + *rstatus = errno; + errno = serrno; + + if (*rstatus == 0) { + /* No digits were found */ + if (nptr == *endptr) + *rstatus = ECANCELED; + /* There are further characters after number */ + else if (**endptr != '\0') + *rstatus = ENOTSUP; + } + + if (im < lo) { + if (*rstatus == 0) + *rstatus = ERANGE; + return lo; + } + if (im > hi) { + if (*rstatus == 0) + *rstatus = ERANGE; + return hi; + } + + return im; +} diff --git a/contrib/blacklist/port/clock_gettime.c b/contrib/blacklist/port/clock_gettime.c new file mode 100644 index 0000000..284bd81 --- /dev/null +++ b/contrib/blacklist/port/clock_gettime.c @@ -0,0 +1,17 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <time.h> +#include <sys/time.h> + +int +clock_gettime(int clock __unused, struct timespec *ts) +{ + struct timeval tv; + if (gettimeofday(&tv, NULL) == -1) + return -1; + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; + return 0; +} diff --git a/contrib/blacklist/port/config.h b/contrib/blacklist/port/config.h new file mode 100644 index 0000000..27f3263 --- /dev/null +++ b/contrib/blacklist/port/config.h @@ -0,0 +1,3 @@ +#if defined(__FreeBSD__) +#include "port.h" +#endif diff --git a/contrib/blacklist/port/configure.ac b/contrib/blacklist/port/configure.ac new file mode 100644 index 0000000..eef8065 --- /dev/null +++ b/contrib/blacklist/port/configure.ac @@ -0,0 +1,91 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT([blacklistd],[0.1],[christos@netbsd.com]) +AM_INIT_AUTOMAKE([subdir-objects foreign]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +AC_SUBST(WARNINGS) + +dnl Checks for programs. +AC_PROG_CC_STDC +AC_USE_SYSTEM_EXTENSIONS +AM_PROG_CC_C_O +AC_C_BIGENDIAN +AC_PROG_INSTALL +AC_PROG_LN_S +LT_INIT([disable-static pic-only]) +gl_VISIBILITY +dnl Checks for headers +AC_HEADER_STDC +AC_HEADER_MAJOR +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(stdint.h fcntl.h stdint.h inttypes.h unistd.h) +AC_CHECK_HEADERS(sys/un.h sys/socket.h limits.h) +AC_CHECK_HEADERS(arpa/inet.h getopt.h err.h) +AC_CHECK_HEADERS(sys/types.h util.h sys/time.h time.h) +AC_CHECK_HEADERS(netatalk/at.h net/if_dl.h db.h db_185.h) +AC_CHECK_LIB(rt, clock_gettime) +AC_CHECK_LIB(db, __db185_open) +AC_CHECK_LIB(util, pidfile) +AC_CHECK_LIB(util, sockaddr_snprintf) + +AH_BOTTOM([ +#ifndef __NetBSD__ +#include "port.h" +#endif +]) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_OFF_T +AC_TYPE_SIZE_T +AC_SYS_LARGEFILE +AC_CHECK_MEMBERS([struct sockaddr.sa_len], [], [], [#include <sys/socket.h>]) + +AC_TYPE_PID_T +AC_TYPE_UINT8_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_INT32_T +AC_TYPE_UINT64_T +AC_TYPE_INT64_T +AC_TYPE_INTPTR_T +AC_TYPE_UINTPTR_T + +AC_MSG_CHECKING(for gcc compiler warnings) +AC_ARG_ENABLE(warnings, +[ --disable-warnings disable compiler warnings], +[if test "${enableval}" = no -o "$GCC" = no; then + AC_MSG_RESULT(no) + WARNINGS= +else + AC_MSG_RESULT(yes) + WARNINGS="-Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith \ + -Wmissing-declarations -Wredundant-decls -Wnested-externs \ + -Wsign-compare -Wreturn-type -Wswitch -Wshadow \ + -Wcast-qual -Wwrite-strings -Wextra -Wunused-parameter -Wformat=2" +fi], [ +if test "$GCC" = yes; then + AC_MSG_RESULT(yes) + WARNINGS="-Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith \ + -Wmissing-declarations -Wredundant-decls -Wnested-externs \ + -Wsign-compare -Wreturn-type -Wswitch -Wshadow \ + -Wcast-qual -Wwrite-strings -Wextra -Wunused-parameter -Wformat=2" +else + WARNINGS= + AC_MSG_RESULT(no) +fi]) + +dnl Checks for functions +AC_CHECK_FUNCS(strerror) + +dnl Provide implementation of some required functions if necessary +AC_REPLACE_FUNCS(strtoi sockaddr_snprintf popenve clock_gettime strlcpy strlcat getprogname fparseln fgetln pidfile) + +dnl See if we are cross-compiling +AM_CONDITIONAL(IS_CROSS_COMPILE, test "$cross_compiling" = yes) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/contrib/blacklist/port/fgetln.c b/contrib/blacklist/port/fgetln.c new file mode 100644 index 0000000..a41a383 --- /dev/null +++ b/contrib/blacklist/port/fgetln.c @@ -0,0 +1,106 @@ +/* $NetBSD: fgetln.c,v 1.1 2015/01/22 03:48:07 christos Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if !HAVE_FGETLN +#include <stdlib.h> +#ifndef HAVE_NBTOOL_CONFIG_H +/* These headers are required, but included from nbtool_config.h */ +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#endif + +char * +fgetln(FILE *fp, size_t *len) +{ + static char *buf = NULL; + static size_t bufsiz = 0; + char *ptr; + + + if (buf == NULL) { + bufsiz = BUFSIZ; + if ((buf = malloc(bufsiz)) == NULL) + return NULL; + } + + if (fgets(buf, bufsiz, fp) == NULL) + return NULL; + + *len = 0; + while ((ptr = strchr(&buf[*len], '\n')) == NULL) { + size_t nbufsiz = bufsiz + BUFSIZ; + char *nbuf = realloc(buf, nbufsiz); + + if (nbuf == NULL) { + int oerrno = errno; + free(buf); + errno = oerrno; + buf = NULL; + return NULL; + } else + buf = nbuf; + + if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL) { + buf[bufsiz] = '\0'; + *len = strlen(buf); + return buf; + } + + *len = bufsiz; + bufsiz = nbufsiz; + } + + *len = (ptr - buf) + 1; + return buf; +} + +#endif + +#ifdef TEST +int +main(int argc, char *argv[]) +{ + char *p; + size_t len; + + while ((p = fgetln(stdin, &len)) != NULL) { + (void)printf("%zu %s", len, p); + free(p); + } + return 0; +} +#endif diff --git a/contrib/blacklist/port/fparseln.c b/contrib/blacklist/port/fparseln.c new file mode 100644 index 0000000..5bfae54b --- /dev/null +++ b/contrib/blacklist/port/fparseln.c @@ -0,0 +1,236 @@ +/* $NetBSD: fparseln.c,v 1.1 2015/01/22 03:48:07 christos Exp $ */ + +/* + * Copyright (c) 1997 Christos Zoulas. 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 ``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 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: fparseln.c,v 1.1 2015/01/22 03:48:07 christos Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#if ! HAVE_FPARSELN || BROKEN_FPARSELN + +#define FLOCKFILE(fp) +#define FUNLOCKFILE(fp) + +#if defined(_REENTRANT) && !HAVE_NBTOOL_CONFIG_H +#define __fgetln(f, l) __fgetstr(f, l, '\n') +#else +#define __fgetln(f, l) fgetln(f, l) +#endif + +static int isescaped(const char *, const char *, int); + +/* isescaped(): + * Return true if the character in *p that belongs to a string + * that starts in *sp, is escaped by the escape character esc. + */ +static int +isescaped(const char *sp, const char *p, int esc) +{ + const char *cp; + size_t ne; + + /* No escape character */ + if (esc == '\0') + return 0; + + /* Count the number of escape characters that precede ours */ + for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++) + continue; + + /* Return true if odd number of escape characters */ + return (ne & 1) != 0; +} + + +/* fparseln(): + * Read a line from a file parsing continuations ending in \ + * and eliminating trailing newlines, or comments starting with + * the comment char. + */ +char * +fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags) +{ + static const char dstr[3] = { '\\', '\\', '#' }; + + size_t s, len; + char *buf; + char *ptr, *cp; + int cnt; + char esc, con, nl, com; + + len = 0; + buf = NULL; + cnt = 1; + + if (str == NULL) + str = dstr; + + esc = str[0]; + con = str[1]; + com = str[2]; + /* + * XXX: it would be cool to be able to specify the newline character, + * but unfortunately, fgetln does not let us + */ + nl = '\n'; + + FLOCKFILE(fp); + + while (cnt) { + cnt = 0; + + if (lineno) + (*lineno)++; + + if ((ptr = __fgetln(fp, &s)) == NULL) + break; + + if (s && com) { /* Check and eliminate comments */ + for (cp = ptr; cp < ptr + s; cp++) + if (*cp == com && !isescaped(ptr, cp, esc)) { + s = cp - ptr; + cnt = s == 0 && buf == NULL; + break; + } + } + + if (s && nl) { /* Check and eliminate newlines */ + cp = &ptr[s - 1]; + + if (*cp == nl) + s--; /* forget newline */ + } + + if (s && con) { /* Check and eliminate continuations */ + cp = &ptr[s - 1]; + + if (*cp == con && !isescaped(ptr, cp, esc)) { + s--; /* forget continuation char */ + cnt = 1; + } + } + + if (s == 0) { + /* + * nothing to add, skip realloc except in case + * we need a minimal buf to return an empty line + */ + if (cnt || buf != NULL) + continue; + } + + if ((cp = realloc(buf, len + s + 1)) == NULL) { + FUNLOCKFILE(fp); + free(buf); + return NULL; + } + buf = cp; + + (void) memcpy(buf + len, ptr, s); + len += s; + buf[len] = '\0'; + } + + FUNLOCKFILE(fp); + + if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL && + strchr(buf, esc) != NULL) { + ptr = cp = buf; + while (cp[0] != '\0') { + int skipesc; + + while (cp[0] != '\0' && cp[0] != esc) + *ptr++ = *cp++; + if (cp[0] == '\0' || cp[1] == '\0') + break; + + skipesc = 0; + if (cp[1] == com) + skipesc += (flags & FPARSELN_UNESCCOMM); + if (cp[1] == con) + skipesc += (flags & FPARSELN_UNESCCONT); + if (cp[1] == esc) + skipesc += (flags & FPARSELN_UNESCESC); + if (cp[1] != com && cp[1] != con && cp[1] != esc) + skipesc = (flags & FPARSELN_UNESCREST); + + if (skipesc) + cp++; + else + *ptr++ = *cp++; + *ptr++ = *cp++; + } + *ptr = '\0'; + len = strlen(buf); + } + + if (size) + *size = len; + return buf; +} + +#ifdef TEST + +int main(int, char **); + +int +main(int argc, char **argv) +{ + char *ptr; + size_t size, line; + + line = 0; + while ((ptr = fparseln(stdin, &size, &line, NULL, + FPARSELN_UNESCALL)) != NULL) + printf("line %d (%d) |%s|\n", line, size, ptr); + return 0; +} + +/* + +# This is a test +line 1 +line 2 \ +line 3 # Comment +line 4 \# Not comment \\\\ + +# And a comment \ +line 5 \\\ +line 6 + +*/ + +#endif /* TEST */ +#endif /* ! HAVE_FPARSELN || BROKEN_FPARSELN */ diff --git a/contrib/blacklist/port/getprogname.c b/contrib/blacklist/port/getprogname.c new file mode 100644 index 0000000..983d674 --- /dev/null +++ b/contrib/blacklist/port/getprogname.c @@ -0,0 +1,24 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <string.h> + +extern char *__progname; + +const char * +getprogname(void) +{ + return __progname; +} + +void +setprogname(char *p) +{ + char *q; + if (p == NULL) + return; + if ((q = strrchr(p, '/')) != NULL) + __progname = ++q; + else + __progname = p; +} diff --git a/contrib/blacklist/port/m4/.cvsignore b/contrib/blacklist/port/m4/.cvsignore new file mode 100644 index 0000000..0f4126c --- /dev/null +++ b/contrib/blacklist/port/m4/.cvsignore @@ -0,0 +1 @@ +*.m4 diff --git a/contrib/blacklist/port/pidfile.c b/contrib/blacklist/port/pidfile.c new file mode 100644 index 0000000..4deb234 --- /dev/null +++ b/contrib/blacklist/port/pidfile.c @@ -0,0 +1,183 @@ +/* $NetBSD: pidfile.c,v 1.2 2016/04/05 12:28:57 christos Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe, Matthias Scheler and Julio Merino. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: pidfile.c,v 1.2 2016/04/05 12:28:57 christos Exp $"); +#endif + +#include <sys/param.h> + +#include <paths.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif +#ifdef HAVE_UTIL_H +#include <util.h> +#endif + +static pid_t pidfile_pid; +static char *pidfile_path; + +/* Deletes an existent pidfile iff it was created by this process. */ +static void +pidfile_cleanup(void) +{ + + if ((pidfile_path != NULL) && (pidfile_pid == getpid())) + (void) unlink(pidfile_path); +} + +/* Registers an atexit(3) handler to delete the pidfile we have generated. + * We only register the handler when we create a pidfile, so we can assume + * that the pidfile exists. + * + * Returns 0 on success or -1 if the handler could not be registered. */ +static int +register_atexit_handler(void) +{ + static bool done = false; + + if (!done) { + if (atexit(pidfile_cleanup) < 0) + return -1; + done = true; + } + + return 0; +} + +/* Given a new pidfile name in 'path', deletes any previously-created pidfile + * if the previous file differs to the new one. + * + * If a previous file is deleted, returns 1, which means that a new pidfile + * must be created. Otherwise, this returns 0, which means that the existing + * file does not need to be touched. */ +static int +cleanup_old_pidfile(const char* path) +{ + if (pidfile_path != NULL) { + if (strcmp(pidfile_path, path) != 0) { + pidfile_cleanup(); + + free(pidfile_path); + pidfile_path = NULL; + + return 1; + } else + return 0; + } else + return 1; +} + +/* Constructs a name for a pidfile in the default location (/var/run). If + * 'basename' is NULL, uses the name of the current program for the name of + * the pidfile. + * + * Returns a pointer to a dynamically-allocatd string containing the absolute + * path to the pidfile; NULL on failure. */ +static char * +generate_varrun_path(const char *bname) +{ + char *path; + + if (bname == NULL) + bname = getprogname(); + + /* _PATH_VARRUN includes trailing / */ + if (asprintf(&path, "%s%s.pid", _PATH_VARRUN, bname) == -1) + return NULL; + return path; +} + +/* Creates a pidfile with the provided name. The new pidfile is "registered" + * in the global variables pidfile_path and pidfile_pid so that any further + * call to pidfile(3) can check if we are recreating the same file or a new + * one. + * + * Returns 0 on success or -1 if there is any error. */ +static int +create_pidfile(const char* path) +{ + FILE *f; + + if (register_atexit_handler() == -1) + return -1; + + if (cleanup_old_pidfile(path) == 0) + return 0; + + pidfile_path = strdup(path); + if (pidfile_path == NULL) + return -1; + + if ((f = fopen(path, "w")) == NULL) { + free(pidfile_path); + pidfile_path = NULL; + return -1; + } + + pidfile_pid = getpid(); + + (void) fprintf(f, "%d\n", pidfile_pid); + (void) fclose(f); + + return 0; +} + +int +pidfile(const char *path) +{ + + if (path == NULL || strchr(path, '/') == NULL) { + char *default_path; + + if ((default_path = generate_varrun_path(path)) == NULL) + return -1; + + if (create_pidfile(default_path) == -1) { + free(default_path); + return -1; + } + + free(default_path); + return 0; + } else + return create_pidfile(path); +} diff --git a/contrib/blacklist/port/popenve.c b/contrib/blacklist/port/popenve.c new file mode 100644 index 0000000..20f6b5b --- /dev/null +++ b/contrib/blacklist/port/popenve.c @@ -0,0 +1,274 @@ +/* $NetBSD: popenve.c,v 1.2 2015/01/22 03:10:50 christos Exp $ */ + +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software written by Ken Arnold and + * published in UNIX Review, Vol. 6, No. 8. + * + * 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 University 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 REGENTS 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 REGENTS 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 5/3/95"; +#else +__RCSID("$NetBSD: popenve.c,v 1.2 2015/01/22 03:10:50 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/wait.h> +#include <sys/socket.h> + +#include <assert.h> +#include <errno.h> +#include <paths.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#ifdef __weak_alias +__weak_alias(popen,_popen) +__weak_alias(pclose,_pclose) +#endif + +static struct pid { + struct pid *next; + FILE *fp; +#ifdef _REENTRANT + int fd; +#endif + pid_t pid; +} *pidlist; + +#ifdef _REENTRANT +static rwlock_t pidlist_lock = RWLOCK_INITIALIZER; +#endif + +static struct pid * +pdes_get(int *pdes, const char **type) +{ + struct pid *cur; + int flags = strchr(*type, 'e') ? O_CLOEXEC : 0; + int serrno; + + if (strchr(*type, '+')) { +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 0 +#endif + int stype = flags ? (SOCK_STREAM | SOCK_CLOEXEC) : SOCK_STREAM; + *type = "r+"; + if (socketpair(AF_LOCAL, stype, 0, pdes) < 0) + return NULL; +#if SOCK_CLOEXEC == 0 + fcntl(pdes[0], F_SETFD, FD_CLOEXEC); + fcntl(pdes[1], F_SETFD, FD_CLOEXEC); +#endif + } else { + *type = strrchr(*type, 'r') ? "r" : "w"; +#if SOCK_CLOEXEC != 0 + if (pipe2(pdes, flags) == -1) + return NULL; +#else + if (pipe(pdes) == -1) + return NULL; + fcntl(pdes[0], F_SETFL, fcntl(pdes[0], F_GETFL) | flags); + fcntl(pdes[1], F_SETFL, fcntl(pdes[1], F_GETFL) | flags); +#endif + } + + if ((cur = malloc(sizeof(*cur))) != NULL) + return cur; + serrno = errno; + (void)close(pdes[0]); + (void)close(pdes[1]); + errno = serrno; + return NULL; +} + +static void +pdes_child(int *pdes, const char *type) +{ + struct pid *old; + + /* POSIX.2 B.3.2.2 "popen() shall ensure that any streams + from previous popen() calls that remain open in the + parent process are closed in the new child process. */ + for (old = pidlist; old; old = old->next) +#ifdef _REENTRANT + (void)close(old->fd); /* don't allow a flush */ +#else + (void)close(fileno(old->fp)); /* don't allow a flush */ +#endif + + if (type[0] == 'r') { + (void)close(pdes[0]); + if (pdes[1] != STDOUT_FILENO) { + (void)dup2(pdes[1], STDOUT_FILENO); + (void)close(pdes[1]); + } + if (type[1] == '+') + (void)dup2(STDOUT_FILENO, STDIN_FILENO); + } else { + (void)close(pdes[1]); + if (pdes[0] != STDIN_FILENO) { + (void)dup2(pdes[0], STDIN_FILENO); + (void)close(pdes[0]); + } + } +} + +static void +pdes_parent(int *pdes, struct pid *cur, pid_t pid, const char *type) +{ + FILE *iop; + + /* Parent; assume fdopen can't fail. */ + if (*type == 'r') { + iop = fdopen(pdes[0], type); +#ifdef _REENTRANT + cur->fd = pdes[0]; +#endif + (void)close(pdes[1]); + } else { + iop = fdopen(pdes[1], type); +#ifdef _REENTRANT + cur->fd = pdes[1]; +#endif + (void)close(pdes[0]); + } + + /* Link into list of file descriptors. */ + cur->fp = iop; + cur->pid = pid; + cur->next = pidlist; + pidlist = cur; +} + +static void +pdes_error(int *pdes, struct pid *cur) +{ + free(cur); + (void)close(pdes[0]); + (void)close(pdes[1]); +} + +FILE * +popenve(const char *cmd, char *const *argv, char *const *envp, const char *type) +{ + struct pid *cur; + int pdes[2], serrno; + pid_t pid; + + if ((cur = pdes_get(pdes, &type)) == NULL) + return NULL; + +#ifdef _REENTRANT + (void)rwlock_rdlock(&pidlist_lock); +#endif + switch (pid = vfork()) { + case -1: /* Error. */ + serrno = errno; +#ifdef _REENTRANT + (void)rwlock_unlock(&pidlist_lock); +#endif + pdes_error(pdes, cur); + errno = serrno; + return NULL; + /* NOTREACHED */ + case 0: /* Child. */ + pdes_child(pdes, type); + execve(cmd, argv, envp); + _exit(127); + /* NOTREACHED */ + } + + pdes_parent(pdes, cur, pid, type); + +#ifdef _REENTRANT + (void)rwlock_unlock(&pidlist_lock); +#endif + + return cur->fp; +} + +/* + * pclose -- + * Pclose returns -1 if stream is not associated with a `popened' command, + * if already `pclosed', or waitpid returns an error. + */ +int +pcloseve(FILE *iop) +{ + struct pid *cur, *last; + int pstat; + pid_t pid; + +#ifdef _REENTRANT + rwlock_wrlock(&pidlist_lock); +#endif + + /* Find the appropriate file pointer. */ + for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next) + if (cur->fp == iop) + break; + if (cur == NULL) { +#ifdef _REENTRANT + (void)rwlock_unlock(&pidlist_lock); +#endif + errno = ESRCH; + return -1; + } + + (void)fclose(iop); + + /* Remove the entry from the linked list. */ + if (last == NULL) + pidlist = cur->next; + else + last->next = cur->next; + +#ifdef _REENTRANT + (void)rwlock_unlock(&pidlist_lock); +#endif + + do { + pid = waitpid(cur->pid, &pstat, 0); + } while (pid == -1 && errno == EINTR); + + free(cur); + + return pid == -1 ? -1 : pstat; +} diff --git a/contrib/blacklist/port/port.h b/contrib/blacklist/port/port.h new file mode 100644 index 0000000..f82fb34 --- /dev/null +++ b/contrib/blacklist/port/port.h @@ -0,0 +1,86 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include <stdio.h> +#include <inttypes.h> +#include <time.h> +#include <sys/stat.h> +#include <netdb.h> + +#ifndef __unused +#define __unused __attribute__((__unused__)) +#endif + +#ifndef __dead +#define __dead __attribute__((__noreturn__)) +#endif + +#ifndef __RCSID +#define __RCSID(a) +#endif + +#ifndef __UNCONST +#define __UNCONST(a) ((void *)(intptr_t)(a)) +#endif + +#ifndef __arraycount +#define __arraycount(a) (sizeof(a) / sizeof(a[0])) +#endif + +#ifndef HAVE_STRLCPY +size_t strlcpy(char *, const char *, size_t); +#endif + +#ifndef HAVE_STRLCAT +size_t strlcat(char *, const char *, size_t); +#endif + +#ifndef HAVE_POPENVE +FILE *popenve(const char *, char *const *, char *const *, const char *); +int pcloseve(FILE *); +#define pclose(a) pcloseve(a); +#endif + +#ifndef HAVE_SOCKADDR_SNPRINTF +struct sockaddr; +int sockaddr_snprintf(char *, size_t, const char *, const struct sockaddr *); +#endif + +#ifndef HAVE_STRTOI +intmax_t strtoi(const char *, char **, int, intmax_t, intmax_t, int *); +#endif + +#ifndef HAVE_GETPROGNAME +const char *getprogname(void); +void setprogname(char *); +#endif + +#ifndef HAVE_PIDFILE +int pidfile(const char *); +#endif + +#ifndef HAVE_FPARSELN +#define FPARSELN_UNESCALL 0xf +#define FPARSELN_UNESCCOMM 0x1 +#define FPARSELN_UNESCCONT 0x2 +#define FPARSELN_UNESCESC 0x4 +#define FPARSELN_UNESCREST 0x8 +char *fparseln(FILE *, size_t *, size_t *, const char delim[3], int); +#endif + +#ifndef HAVE_FGETLN +char *fgetln(FILE *, size_t *); +#endif + +#ifndef HAVE_CLOCK_GETTIME +struct timespec; +int clock_gettime(int, struct timespec *); +#define CLOCK_REALTIME 0 +#endif + +#if !defined(__FreeBSD__) +#define _PATH_BLCONF "conf" +#define _PATH_BLCONTROL "control" +#define _PATH_BLSOCK "blacklistd.sock" +#define _PATH_BLSTATE "blacklistd.db" +#endif diff --git a/contrib/blacklist/port/sockaddr_snprintf.c b/contrib/blacklist/port/sockaddr_snprintf.c new file mode 100644 index 0000000..41e5e0c --- /dev/null +++ b/contrib/blacklist/port/sockaddr_snprintf.c @@ -0,0 +1,383 @@ +/* $NetBSD: sockaddr_snprintf.c,v 1.10 2016/04/05 12:28:57 christos Exp $ */ + +/*- + * Copyright (c) 2004 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: sockaddr_snprintf.c,v 1.10 2016/04/05 12:28:57 christos Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <netinet/in.h> +#ifdef __linux__ +#undef HAVE_NETATALK_AT_H +#endif +#ifdef HAVE_NETATALK_AT_H +#include <netatalk/at.h> +#endif +#ifdef HAVE_NET_IF_DL_H +#include <net/if_dl.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif +#ifdef HAVE_UTIL_H +#include <util.h> +#endif +#include <netdb.h> + +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN +#define SLEN(a) (a)->a ## _len +#else +static socklen_t +socklen(u_int af) +{ + switch (af) { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + case AF_LOCAL: + return sizeof(struct sockaddr_un); +#ifdef HAVE_NET_IF_DL_H + case AF_LINK: + return sizeof(struct sockaddr_dl); +#endif +#ifdef HAVE_NETATALK_AT_H + case AF_APPLETALK: + return sizeof(struct sockaddr_at); +#endif + default: + return sizeof(struct sockaddr_storage); + } +} + +#define SLEN(a) socklen((a)->a ## _family) +#endif + +#ifdef HAVE_NETATALK_AT_H +static int +debug_at(char *str, size_t len, const struct sockaddr_at *sat) +{ + return snprintf(str, len, "sat_len=%u, sat_family=%u, sat_port=%u, " + "sat_addr.s_net=%u, sat_addr.s_node=%u, " + "sat_range.r_netrange.nr_phase=%u, " + "sat_range.r_netrange.nr_firstnet=%u, " + "sat_range.r_netrange.nr_lastnet=%u", + SLEN(sat), sat->sat_family, sat->sat_port, + sat->sat_addr.s_net, sat->sat_addr.s_node, + sat->sat_range.r_netrange.nr_phase, + sat->sat_range.r_netrange.nr_firstnet, + sat->sat_range.r_netrange.nr_lastnet); +} +#endif + +static int +debug_in(char *str, size_t len, const struct sockaddr_in *sin) +{ + return snprintf(str, len, "sin_len=%u, sin_family=%u, sin_port=%u, " + "sin_addr.s_addr=%08x", + SLEN(sin), sin->sin_family, sin->sin_port, + sin->sin_addr.s_addr); +} + +static int +debug_in6(char *str, size_t len, const struct sockaddr_in6 *sin6) +{ + const uint8_t *s = sin6->sin6_addr.s6_addr; + + return snprintf(str, len, "sin6_len=%u, sin6_family=%u, sin6_port=%u, " + "sin6_flowinfo=%u, " + "sin6_addr=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:" + "%02x:%02x:%02x:%02x:%02x:%02x, sin6_scope_id=%u", + SLEN(sin6), sin6->sin6_family, sin6->sin6_port, + sin6->sin6_flowinfo, s[0x0], s[0x1], s[0x2], s[0x3], s[0x4], s[0x5], + s[0x6], s[0x7], s[0x8], s[0x9], s[0xa], s[0xb], s[0xc], s[0xd], + s[0xe], s[0xf], sin6->sin6_scope_id); +} + +static int +debug_un(char *str, size_t len, const struct sockaddr_un *sun) +{ + return snprintf(str, len, "sun_len=%u, sun_family=%u, sun_path=%*s", + SLEN(sun), sun->sun_family, (int)sizeof(sun->sun_path), + sun->sun_path); +} + +#ifdef HAVE_NET_IF_DL_H +static int +debug_dl(char *str, size_t len, const struct sockaddr_dl *sdl) +{ + const uint8_t *s = (const void *)sdl->sdl_data; + + return snprintf(str, len, "sdl_len=%u, sdl_family=%u, sdl_index=%u, " + "sdl_type=%u, sdl_nlen=%u, sdl_alen=%u, sdl_slen=%u, sdl_data=" + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + SLEN(sdl), sdl->sdl_family, sdl->sdl_index, + sdl->sdl_type, sdl->sdl_nlen, sdl->sdl_alen, sdl->sdl_slen, + s[0x0], s[0x1], s[0x2], s[0x3], s[0x4], s[0x5], + s[0x6], s[0x7], s[0x8], s[0x9], s[0xa], s[0xb]); +} +#endif + +int +sockaddr_snprintf(char * const sbuf, const size_t len, const char * const fmt, + const struct sockaddr * const sa) +{ + const void *a = NULL; + char abuf[1024], nbuf[1024], *addr = NULL; + + char Abuf[1024], pbuf[32], *name = NULL, *port = NULL; + char *ebuf = &sbuf[len - 1], *buf = sbuf; + const char *ptr, *s; + int p = -1; +#ifdef HAVE_NETATALK_AT_H + const struct sockaddr_at *sat = NULL; +#endif + const struct sockaddr_in *sin4 = NULL; + const struct sockaddr_in6 *sin6 = NULL; + const struct sockaddr_un *sun = NULL; +#ifdef HAVE_NET_IF_DL_H + const struct sockaddr_dl *sdl = NULL; + char *w = NULL; +#endif + int na = 1; + +#define ADDC(c) do { if (buf < ebuf) *buf++ = c; else buf++; } \ + while (/*CONSTCOND*/0) +#define ADDS(p) do { for (s = p; *s; s++) ADDC(*s); } \ + while (/*CONSTCOND*/0) +#define ADDNA() do { if (na) ADDS("N/A"); } \ + while (/*CONSTCOND*/0) + + switch (sa->sa_family) { + case AF_UNSPEC: + goto done; +#ifdef HAVE_NETATALK_AT_H + case AF_APPLETALK: + sat = ((const struct sockaddr_at *)(const void *)sa); + p = ntohs(sat->sat_port); + (void)snprintf(addr = abuf, sizeof(abuf), "%u.%u", + ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node); + (void)snprintf(port = pbuf, sizeof(pbuf), "%d", p); + break; +#endif + case AF_LOCAL: + sun = ((const struct sockaddr_un *)(const void *)sa); + (void)strlcpy(addr = abuf, sun->sun_path, sizeof(abuf)); + break; + case AF_INET: + sin4 = ((const struct sockaddr_in *)(const void *)sa); + p = ntohs(sin4->sin_port); + a = &sin4->sin_addr; + break; + case AF_INET6: + sin6 = ((const struct sockaddr_in6 *)(const void *)sa); + p = ntohs(sin6->sin6_port); + a = &sin6->sin6_addr; + break; +#ifdef HAVE_NET_IF_DL_H + case AF_LINK: + sdl = ((const struct sockaddr_dl *)(const void *)sa); + (void)strlcpy(addr = abuf, link_ntoa(sdl), sizeof(abuf)); + if ((w = strchr(addr, ':')) != 0) { + *w++ = '\0'; + addr = w; + } + break; +#endif + default: + errno = EAFNOSUPPORT; + return -1; + } + + if (addr == abuf) + name = addr; + + if (a && getnameinfo(sa, (socklen_t)SLEN(sa), addr = abuf, + (unsigned int)sizeof(abuf), NULL, 0, + NI_NUMERICHOST|NI_NUMERICSERV) != 0) + return -1; + + for (ptr = fmt; *ptr; ptr++) { + if (*ptr != '%') { + ADDC(*ptr); + continue; + } + next_char: + switch (*++ptr) { + case '?': + na = 0; + goto next_char; + case 'a': + ADDS(addr); + break; + case 'p': + if (p != -1) { + (void)snprintf(nbuf, sizeof(nbuf), "%d", p); + ADDS(nbuf); + } else + ADDNA(); + break; + case 'f': + (void)snprintf(nbuf, sizeof(nbuf), "%d", sa->sa_family); + ADDS(nbuf); + break; + case 'l': + (void)snprintf(nbuf, sizeof(nbuf), "%d", SLEN(sa)); + ADDS(nbuf); + break; + case 'A': + if (name) + ADDS(name); + else if (!a) + ADDNA(); + else { + getnameinfo(sa, (socklen_t)SLEN(sa), + name = Abuf, + (unsigned int)sizeof(nbuf), NULL, 0, 0); + ADDS(name); + } + break; + case 'P': + if (port) + ADDS(port); + else if (p == -1) + ADDNA(); + else { + getnameinfo(sa, (socklen_t)SLEN(sa), NULL, 0, + port = pbuf, + (unsigned int)sizeof(pbuf), 0); + ADDS(port); + } + break; + case 'I': +#ifdef HAVE_NET_IF_DL_H + if (sdl && addr != abuf) { + ADDS(abuf); + } else +#endif + { + ADDNA(); + } + break; + case 'F': + if (sin6) { + (void)snprintf(nbuf, sizeof(nbuf), "%d", + sin6->sin6_flowinfo); + ADDS(nbuf); + break; + } else { + ADDNA(); + } + break; + case 'S': + if (sin6) { + (void)snprintf(nbuf, sizeof(nbuf), "%d", + sin6->sin6_scope_id); + ADDS(nbuf); + break; + } else { + ADDNA(); + } + break; + case 'R': +#ifdef HAVE_NETATALK_AT_H + if (sat) { + const struct netrange *n = + &sat->sat_range.r_netrange; + (void)snprintf(nbuf, sizeof(nbuf), + "%d:[%d,%d]", n->nr_phase , n->nr_firstnet, + n->nr_lastnet); + ADDS(nbuf); + } else +#endif + { + ADDNA(); + } + break; + case 'D': + switch (sa->sa_family) { +#ifdef HAVE_NETATALK_AT_H + case AF_APPLETALK: + debug_at(nbuf, sizeof(nbuf), sat); + break; +#endif + case AF_LOCAL: + debug_un(nbuf, sizeof(nbuf), sun); + break; + case AF_INET: + debug_in(nbuf, sizeof(nbuf), sin4); + break; + case AF_INET6: + debug_in6(nbuf, sizeof(nbuf), sin6); + break; +#ifdef HAVE_NET_IF_DL_H + case AF_LINK: + debug_dl(nbuf, sizeof(nbuf), sdl); + break; +#endif + default: + abort(); + } + ADDS(nbuf); + break; + default: + ADDC('%'); + if (na == 0) + ADDC('?'); + if (*ptr == '\0') + goto done; + /*FALLTHROUGH*/ + case '%': + ADDC(*ptr); + break; + } + na = 1; + } +done: + if (buf < ebuf) + *buf = '\0'; + else if (len != 0) + sbuf[len - 1] = '\0'; + return (int)(buf - sbuf); +} diff --git a/contrib/blacklist/port/strlcat.c b/contrib/blacklist/port/strlcat.c new file mode 100644 index 0000000..d3c69b5 --- /dev/null +++ b/contrib/blacklist/port/strlcat.c @@ -0,0 +1,96 @@ +/* $NetBSD: strlcat.c,v 1.2 2015/01/22 03:48:07 christos Exp $ */ +/* $OpenBSD: strlcat.c,v 1.10 2003/04/12 21:56:39 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(_KERNEL) && !defined(_STANDALONE) +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: strlcat.c,v 1.2 2015/01/22 03:48:07 christos Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#ifdef _LIBC +#include "namespace.h" +#endif +#include <sys/types.h> +#include <assert.h> +#include <string.h> + +#ifdef _LIBC +# ifdef __weak_alias +__weak_alias(strlcat, _strlcat) +# endif +#endif + +#else +#include <lib/libkern/libkern.h> +#endif /* !_KERNEL && !_STANDALONE */ + +#if !HAVE_STRLCAT +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t siz) +{ +#if 1 + char *d = dst; + const char *s = src; + size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +#else + + /* + * Find length of string in dst (maxing out at siz). + */ + size_t dlen = strnlen(dst, siz); + + /* + * Copy src into any remaining space in dst (truncating if needed). + * Note strlcpy(dst, src, 0) returns strlen(src). + */ + return dlen + strlcpy(dst + dlen, src, siz - dlen); +#endif +} +#endif diff --git a/contrib/blacklist/port/strlcpy.c b/contrib/blacklist/port/strlcpy.c new file mode 100644 index 0000000..6646e1c --- /dev/null +++ b/contrib/blacklist/port/strlcpy.c @@ -0,0 +1,78 @@ +/* $NetBSD: strlcpy.c,v 1.2 2015/01/22 03:48:07 christos Exp $ */ +/* $OpenBSD: strlcpy.c,v 1.7 2003/04/12 21:56:39 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(_KERNEL) && !defined(_STANDALONE) +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: strlcpy.c,v 1.2 2015/01/22 03:48:07 christos Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#ifdef _LIBC +#include "namespace.h" +#endif +#include <sys/types.h> +#include <assert.h> +#include <string.h> + +#ifdef _LIBC +# ifdef __weak_alias +__weak_alias(strlcpy, _strlcpy) +# endif +#endif +#else +#include <lib/libkern/libkern.h> +#endif /* !_KERNEL && !_STANDALONE */ + + +#if !HAVE_STRLCPY +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} +#endif diff --git a/contrib/blacklist/port/strtoi.c b/contrib/blacklist/port/strtoi.c new file mode 100644 index 0000000..5514f1a --- /dev/null +++ b/contrib/blacklist/port/strtoi.c @@ -0,0 +1,61 @@ +/* $NetBSD: strtoi.c,v 1.3 2015/01/22 03:10:50 christos Exp $ */ + +/*- + * Copyright (c) 2005 The DragonFly Project. All rights reserved. + * Copyright (c) 2003 Citrus 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. + * + * 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. + * + * Created by Kamil Rytarowski, based on ID: + * NetBSD: src/common/lib/libc/stdlib/strtoul.c,v 1.3 2008/08/20 19:58:34 oster Exp + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: strtoi.c,v 1.3 2015/01/22 03:10:50 christos Exp $"); + +#if defined(_KERNEL) +#include <sys/param.h> +#include <sys/types.h> +#include <lib/libkern/libkern.h> +#elif defined(_STANDALONE) +#include <sys/param.h> +#include <sys/types.h> +#include <lib/libkern/libkern.h> +#include <lib/libsa/stand.h> +#else +#include <stddef.h> +#include <assert.h> +#include <errno.h> +#include <inttypes.h> +#endif + +#define _FUNCNAME strtoi +#define __TYPE intmax_t +#define __WRAPPED strtoimax + +#if !HAVE_STRTOI +#include "_strtoi.h" +#endif diff --git a/contrib/blacklist/test/Makefile b/contrib/blacklist/test/Makefile new file mode 100644 index 0000000..a451274 --- /dev/null +++ b/contrib/blacklist/test/Makefile @@ -0,0 +1,12 @@ +# $NetBSD: Makefile,v 1.3 2015/05/30 22:40:38 christos Exp $ + +MKMAN=no + +PROGS=srvtest cltest +SRCS.srvtest = srvtest.c +SRCS.cltest = cltest.c +CPPFLAGS+=-DBLDEBUG +LDADD+=-lutil +DPADD+=${LIBUTIL} + +.include <bsd.prog.mk> diff --git a/contrib/blacklist/test/cltest.c b/contrib/blacklist/test/cltest.c new file mode 100644 index 0000000..6671429 --- /dev/null +++ b/contrib/blacklist/test/cltest.c @@ -0,0 +1,136 @@ +/* $NetBSD: cltest.c,v 1.6 2015/01/22 05:44:28 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: cltest.c,v 1.6 2015/01/22 05:44:28 christos Exp $"); + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <err.h> +#ifdef HAVE_UTIL_H +#include <util.h> +#endif + +static __dead void +usage(int c) +{ + warnx("Unknown option `%c'", (char)c); + fprintf(stderr, "Usage: %s [-u] [-a <addr>] [-m <msg>] [-p <port>]\n", + getprogname()); + exit(EXIT_FAILURE); +} + +static void +getaddr(const char *a, in_port_t p, struct sockaddr_storage *ss, + socklen_t *slen) +{ + int c; + + memset(ss, 0, sizeof(*ss)); + p = htons(p); + + if (strchr(a, ':')) { + struct sockaddr_in6 *s6 = (void *)ss; + c = inet_pton(AF_INET6, a, &s6->sin6_addr); + s6->sin6_family = AF_INET6; + *slen = sizeof(*s6); + s6->sin6_port = p; + } else { + struct sockaddr_in *s = (void *)ss; + c = inet_pton(AF_INET, a, &s->sin_addr); + s->sin_family = AF_INET; + *slen = sizeof(*s); + s->sin_port = p; + } +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + ss->ss_len = (uint8_t)*slen; +#endif + if (c == -1) + err(EXIT_FAILURE, "Invalid address `%s'", a); +} + +int +main(int argc, char *argv[]) +{ + int sfd; + int c; + struct sockaddr_storage ss; + const char *msg = "hello"; + const char *addr = "127.0.0.1"; + int type = SOCK_STREAM; + in_port_t port = 6161; + socklen_t slen; + char buf[128]; + + while ((c = getopt(argc, argv, "a:m:p:u")) != -1) { + switch (c) { + case 'a': + addr = optarg; + break; + case 'm': + msg = optarg; + break; + case 'p': + port = (in_port_t)atoi(optarg); + break; + case 'u': + type = SOCK_DGRAM; + break; + default: + usage(c); + } + } + + getaddr(addr, port, &ss, &slen); + + if ((sfd = socket(AF_INET, type, 0)) == -1) + err(EXIT_FAILURE, "socket"); + + sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (const void *)&ss); + printf("connecting to: %s\n", buf); + if (connect(sfd, (const void *)&ss, slen) == -1) + err(EXIT_FAILURE, "connect"); + + size_t len = strlen(msg) + 1; + if (write(sfd, msg, len) != (ssize_t)len) + err(EXIT_FAILURE, "write"); + return 0; +} diff --git a/contrib/blacklist/test/srvtest.c b/contrib/blacklist/test/srvtest.c new file mode 100644 index 0000000..03a762a --- /dev/null +++ b/contrib/blacklist/test/srvtest.c @@ -0,0 +1,220 @@ +/* $NetBSD: srvtest.c,v 1.10 2015/05/30 22:40:38 christos Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: srvtest.c,v 1.10 2015/05/30 22:40:38 christos Exp $"); + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include <stdio.h> +#include <signal.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include <stdlib.h> +#include <poll.h> +#include <err.h> + +#include "blacklist.h" +#ifdef BLDEBUG +#include "bl.h" +static void *b; +#endif + +#ifndef INFTIM +#define INFTIM -1 +#endif + +static void +process_tcp(int afd) +{ + ssize_t n; + char buffer[256]; + + memset(buffer, 0, sizeof(buffer)); + + if ((n = read(afd, buffer, sizeof(buffer))) == -1) + err(1, "read"); + buffer[sizeof(buffer) - 1] = '\0'; + printf("%s: sending %d %s\n", getprogname(), afd, buffer); +#ifdef BLDEBUG + blacklist_r(b, 1, afd, buffer); +#else + blacklist(1, afd, buffer); +#endif + exit(0); +} + +static void +process_udp(int afd) +{ + ssize_t n; + char buffer[256]; + struct sockaddr_storage ss; + socklen_t slen; + + memset(buffer, 0, sizeof(buffer)); + + slen = (socklen_t)sizeof(ss); + memset(&ss, 0, sizeof(ss)); + if ((n = recvfrom(afd, buffer, sizeof(buffer), 0, (void *)&ss, + &slen)) == -1) + err(1, "recvfrom"); + buffer[sizeof(buffer) - 1] = '\0'; + printf("%s: sending %d %s\n", getprogname(), afd, buffer); + blacklist_sa(1, afd, (void *)&ss, slen, buffer); + exit(0); +} +static int +cr(int af, int type, in_port_t p) +{ + int sfd; + struct sockaddr_storage ss; + socklen_t slen; + sfd = socket(af == AF_INET ? PF_INET : PF_INET6, type, 0); + if (sfd == -1) + err(1, "socket"); + + p = htons(p); + memset(&ss, 0, sizeof(ss)); + if (af == AF_INET) { + struct sockaddr_in *s = (void *)&ss; + s->sin_family = AF_INET; + slen = sizeof(*s); + s->sin_port = p; + } else { + struct sockaddr_in6 *s6 = (void *)&ss; + s6->sin6_family = AF_INET6; + slen = sizeof(*s6); + s6->sin6_port = p; + } +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + ss.ss_len = (uint8_t)slen; +#endif + + if (bind(sfd, (const void *)&ss, slen) == -1) + err(1, "bind"); + + if (type != SOCK_DGRAM) + if (listen(sfd, 5) == -1) + err(1, "listen"); + return sfd; +} + +static void +handle(int type, int sfd) +{ + struct sockaddr_storage ss; + socklen_t alen = sizeof(ss); + int afd; + + if (type != SOCK_DGRAM) { + if ((afd = accept(sfd, (void *)&ss, &alen)) == -1) + err(1, "accept"); + } else + afd = sfd; + + /* Create child process */ + switch (fork()) { + case -1: + err(1, "fork"); + case 0: + if (type == SOCK_DGRAM) + process_udp(afd); + else + process_tcp(afd); + break; + default: + close(afd); + break; + } +} + +static __dead void +usage(int c) +{ + warnx("Unknown option `%c'", (char)c); + fprintf(stderr, "Usage: %s [-u] [-p <num>]\n", getprogname()); + exit(EXIT_FAILURE); +} + +int +main(int argc, char *argv[]) +{ +#ifdef __linux__ +#define NUMFD 1 +#else +#define NUMFD 2 +#endif + struct pollfd pfd[NUMFD]; + int type = SOCK_STREAM, c; + in_port_t port = 6161; + + signal(SIGCHLD, SIG_IGN); + +#ifdef BLDEBUG + b = bl_create(false, "blsock", vsyslog); +#endif + + while ((c = getopt(argc, argv, "up:")) != -1) + switch (c) { + case 'u': + type = SOCK_DGRAM; + break; + case 'p': + port = (in_port_t)atoi(optarg); + break; + default: + usage(c); + } + + pfd[0].fd = cr(AF_INET, type, port); + pfd[0].events = POLLIN; +#if NUMFD > 1 + pfd[1].fd = cr(AF_INET6, type, port); + pfd[1].events = POLLIN; +#endif + + for (;;) { + if (poll(pfd, __arraycount(pfd), INFTIM) == -1) + err(1, "poll"); + for (size_t i = 0; i < __arraycount(pfd); i++) { + if ((pfd[i].revents & POLLIN) == 0) + continue; + handle(type, pfd[i].fd); + } + } +} diff --git a/contrib/libxo/configure.ac b/contrib/libxo/configure.ac index d1db438..0ff0a64 100644 --- a/contrib/libxo/configure.ac +++ b/contrib/libxo/configure.ac @@ -12,7 +12,7 @@ # AC_PREREQ(2.2) -AC_INIT([libxo], [0.6.1], [phil@juniper.net]) +AC_INIT([libxo], [0.6.2], [phil@juniper.net]) AM_INIT_AUTOMAKE([-Wall -Werror foreign -Wno-portability]) # Support silent build rules. Requires at least automake-1.11. diff --git a/contrib/libxo/doc/libxo-manual.html b/contrib/libxo/doc/libxo-manual.html index 4db374b..0c042a4 100644 --- a/contrib/libxo/doc/libxo-manual.html +++ b/contrib/libxo/doc/libxo-manual.html @@ -515,7 +515,7 @@ li.indline1 { } @top-right { - content: "April 2016"; + content: "May 2016"; } @top-center { @@ -22009,7 +22009,7 @@ jQuery(function ($) { </tr> <tr> <td class="header left"></td> -<td class="header right">April 15, 2016</td> +<td class="header right">May 28, 2016</td> </tr> </table></div> <p id="title" class="title">libxo: The Easy Way to Generate text, XML, JSON, and HTML output<br><span class="filename">libxo-manual</span></p> @@ -22739,7 +22739,7 @@ jQuery(function ($) { make make test sudo make install - </pre> <p id="doc_section_1_1_2_p_4">The following sections will walk thru each of these steps with additional details and options, but the above directions should be all that's needed.</p> + </pre> <p id="doc_section_1_1_2_p_4">The following sections will walk through each of these steps with additional details and options, but the above directions should be all that's needed.</p> <p id="doc_section_1_1_2_p_5">Section Contents: </p> <ul> <li><a href="#setting-up-the-build" title="Setting up the build">Section 1.1.2.1</a></li> @@ -23087,7 +23087,7 @@ jQuery(function ($) { xo_emit("{L:Free}{D::}{P: }{:free/%u} {U:Blocks}\n", free_blocks); </pre> <p id="doc_section_2_2_1_p_3">When a role is not provided, the "value" role is used as the default.</p> -<p id="doc_section_2_2_1_p_4">Roles and modifiers can also use more verbose names, when preceeded by a comma:</p> +<p id="doc_section_2_2_1_p_4">Roles and modifiers can also use more verbose names, when preceded by a comma:</p> <div id="doc_figure_u.27"></div> <pre> EXAMPLE: xo_emit("{,label:Free}{,decoration::}{,padding: }" @@ -23444,7 +23444,7 @@ jQuery(function ($) { </tr> </tbody> </table></div> -<p id="doc_section_2_2_2_p_2">Roles and modifiers can also use more verbose names, when preceeded by a comma. For example, the modifier string "Lwc" (or "L,white,colon") means the field has a label role (text that describes the next field) and should be followed by a colon ('c') and a space ('w'). The modifier string "Vkq" (or ":key,quote") means the field has a value role (the default role), that it is a key for the current instance, and that the value should be quoted when encoded for JSON.</p> +<p id="doc_section_2_2_2_p_2">Roles and modifiers can also use more verbose names, when preceded by a comma. For example, the modifier string "Lwc" (or "L,white,colon") means the field has a label role (text that describes the next field) and should be followed by a colon ('c') and a space ('w'). The modifier string "Vkq" (or ":key,quote") means the field has a value role (the default role), that it is a key for the current instance, and that the value should be quoted when encoded for JSON.</p> <p id="doc_section_2_2_2_p_3">Section Contents: </p> <ul> <li><a href="#the-argument-modifier-a" title="The Argument Modifier ({a:})">Section 2.2.2.1</a></li> @@ -23688,7 +23688,7 @@ jQuery(function ($) { <li>a '#' character, indicating the output value should be prefixed with '0x', typically to indicate a base 16 (hex) value.</li> <li>a minus sign ('‑'), indicating the output value should be padded on the right instead of the left.</li> <li>a leading zero ('0') indicating the output value should be padded on the left with zeroes instead of spaces (' ').</li> -<li>one or more digits ('0' - '9') indicating the minimum width of the argument. If the width in columns of the output value is less that the minumum width, the value will be padded to reach the minimum.</li> +<li>one or more digits ('0' - '9') indicating the minimum width of the argument. If the width in columns of the output value is less than the minimum width, the value will be padded to reach the minimum.</li> <li>a period followed by one or more digits indicating the maximum number of bytes which will be examined for a string argument, or the maximum width for a non-string argument. When handling ASCII strings this functions as the field width but for multi-byte characters, a single character may be composed of multiple bytes. xo_emit will never dereference memory beyond the given number of bytes.</li> <li>a second period followed by one or more digits indicating the maximum width for a string argument. This modifier cannot be given for non-string arguments.</li> <li>one or more 'h' characters, indicating shorter input data.</li> diff --git a/contrib/libxo/doc/libxo.txt b/contrib/libxo/doc/libxo.txt index ba63702..4cd51cc 100644 --- a/contrib/libxo/doc/libxo.txt +++ b/contrib/libxo/doc/libxo.txt @@ -155,7 +155,7 @@ explained in detail in the rest of this section. make test sudo make install -The following sections will walk thru each of these steps with +The following sections will walk through each of these steps with additional details and options, but the above directions should be all that's needed. @@ -469,7 +469,7 @@ content. The roles are listed below; only one role is permitted: When a role is not provided, the "value" role is used as the default. -Roles and modifiers can also use more verbose names, when preceeded by +Roles and modifiers can also use more verbose names, when preceded by a comma: EXAMPLE: @@ -720,7 +720,7 @@ particular output styles: | w | white | A blank (" ") is appended after the label | |---+---------------+--------------------------------------------------| -Roles and modifiers can also use more verbose names, when preceeded by +Roles and modifiers can also use more verbose names, when preceded by a comma. For example, the modifier string "Lwc" (or "L,white,colon") means the field has a label role (text that describes the next field) and should be followed by a colon ('c') and a space ('w'). The @@ -986,8 +986,8 @@ the right instead of the left. - a leading zero ('0') indicating the output value should be padded on the left with zeroes instead of spaces (' '). - one or more digits ('0' - '9') indicating the minimum width of the -argument. If the width in columns of the output value is less that -the minumum width, the value will be padded to reach the minimum. +argument. If the width in columns of the output value is less than +the minimum width, the value will be padded to reach the minimum. - a period followed by one or more digits indicating the maximum number of bytes which will be examined for a string argument, or the maximum width for a non-string argument. When handling ASCII strings this diff --git a/contrib/libxo/libxo/libxo.c b/contrib/libxo/libxo/libxo.c index 194a096..7a714b1 100644 --- a/contrib/libxo/libxo/libxo.c +++ b/contrib/libxo/libxo/libxo.c @@ -56,7 +56,7 @@ * (end of word, middle of word, etc) and many that affect characters * previously emitted. Without content, it can't hope to tell us. * But it's the only standard tool we've got, so we use it. We would - * use wcswidth() but it typically just loops thru adding the results + * use wcswidth() but it typically just loops through adding the results * of wcwidth() calls in an entirely unhelpful way. * * Even then, there are many poor implementations (macosx), so we have @@ -97,7 +97,7 @@ /* * Three styles of specifying thread-local variables are supported. - * configure.ac has the brains to run each possibility thru the + * configure.ac has the brains to run each possibility through the * compiler and see what works; we are left to define the THREAD_LOCAL * macro to the right value. Most toolchains (clang, gcc) use * "before", but some (borland) use "after" and I've heard of some @@ -988,7 +988,7 @@ xo_vsnprintf (xo_handle_t *xop, xo_buffer_t *xbp, const char *fmt, va_list vap) } /* - * Print some data thru the handle. + * Print some data through the handle. */ static int xo_printf_v (xo_handle_t *xop, const char *fmt, va_list vap) @@ -1251,7 +1251,7 @@ xo_buf_append_locale (xo_handle_t *xop, xo_buffer_t *xbp, cols += xo_buf_append_locale_from_utf8(xop, xbp, cp, slen); - /* Next time thru, we'll start at the next character */ + /* Next time through, we'll start at the next character */ cp += slen - 1; sp = cp + 1; } @@ -2816,7 +2816,7 @@ xo_format_string (xo_handle_t *xop, xo_buffer_t *xbp, xo_xff_flags_t flags, * but if we did the work ourselves, then we need to do it. */ int delta = xfp->xf_width[XF_WIDTH_MIN] - cols; - if (!xo_buf_has_room(xbp, delta)) + if (!xo_buf_has_room(xbp, xfp->xf_width[XF_WIDTH_MIN])) goto bail; /* @@ -3328,7 +3328,7 @@ xo_do_format_field (xo_handle_t *xop, xo_buffer_t *xbp, case XO_STYLE_XML: if (flags & XFF_TRIM_WS) columns = rc = xo_trim_ws(xbp, rc); - /* fall thru */ + /* FALLTHRU */ case XO_STYLE_HTML: rc = xo_escape_xml(xbp, rc, (flags & XFF_ATTR)); break; @@ -3687,7 +3687,7 @@ xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags, if (flags & XFF_ENCODE_ONLY) { /* - * Even if this is encode-only, we need to go thru the + * Even if this is encode-only, we need to go through the * work of formatting it to make sure the args are cleared * from xo_vap. */ @@ -5342,7 +5342,7 @@ xo_gettext_finish_numbering_fields (xo_handle_t *xop UNUSED, } /* - * The format string uses field numbers, so we need to whiffle thru it + * The format string uses field numbers, so we need to whiffle through it * and make sure everything's sane and lovely. */ static int @@ -6128,6 +6128,12 @@ xo_do_emit_fields (xo_handle_t *xop, xo_field_info_t *fields, XOIF_CLEAR(xop, XOIF_REORDER); + /* + * If we've got enough data, flush it. + */ + if (xo_buf_offset(&xop->xo_data) > XO_BUF_HIGH_WATER) + flush = 1; + /* If we don't have an anchor, write the text out */ if (flush && !XOIF_ISSET(xop, XOIF_ANCHOR)) { if (xo_write(xop) < 0) @@ -6988,7 +6994,7 @@ xo_do_close_leaf_list (xo_handle_t *xop, const char *name) case XO_STYLE_ENCODER: rc = xo_encoder_handle(xop, XO_OP_CLOSE_LEAF_LIST, name, NULL); - /*fallthru*/ + /* FALLTHRU */ default: xo_depth_change(xop, name, -1, 0, XSS_CLOSE_LEAF_LIST, XSF_LIST); @@ -7780,9 +7786,9 @@ xo_parse_args (int argc, char **argv) } cp = argv[i] + sizeof(libxo_opt) - 1; - if (*cp == 0) { + if (*cp == '\0') { cp = argv[++i]; - if (cp == 0) { + if (cp == NULL) { xo_warnx("missing libxo option"); return -1; } @@ -7879,7 +7885,7 @@ xo_set_version_h (xo_handle_t *xop, const char *version) } /* - * Set the version number for the API content being carried thru + * Set the version number for the API content being carried through * the xo handle. */ void diff --git a/contrib/libxo/libxo/xo_buf.h b/contrib/libxo/libxo/xo_buf.h index 349e9ad..01eb397 100644 --- a/contrib/libxo/libxo/xo_buf.h +++ b/contrib/libxo/libxo/xo_buf.h @@ -19,8 +19,8 @@ #ifndef XO_BUF_H #define XO_BUF_H -#define XO_BUFSIZ (8*1024) /* Initial buffer size */ - +#define XO_BUFSIZ (8*1024) /* Initial buffer size */ +#define XO_BUF_HIGH_WATER (XO_BUFSIZ - 512) /* When to auto-flush */ /* * xo_buffer_t: a memory buffer that can be grown as needed. We * use them for building format strings and output data. diff --git a/contrib/libxo/libxo/xo_encoder.c b/contrib/libxo/libxo/xo_encoder.c index 70195ec..eb2960b 100644 --- a/contrib/libxo/libxo/xo_encoder.c +++ b/contrib/libxo/libxo/xo_encoder.c @@ -313,7 +313,7 @@ xo_encoder_init (xo_handle_t *xop, const char *name) /* * A couple of function varieties here, to allow for multiple - * use cases. This varient is for when the main program knows + * use cases. This variant is for when the main program knows * its own encoder needs. */ xo_handle_t * diff --git a/contrib/libxo/libxo/xo_format.5 b/contrib/libxo/libxo/xo_format.5 index 79af3fa..abd1b6f 100644 --- a/contrib/libxo/libxo/xo_format.5 +++ b/contrib/libxo/libxo/xo_format.5 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd November 6, 2015 +.Dd December 4, 2014 .Dt LIBXO 3 .Os .Sh NAME @@ -116,7 +116,7 @@ The roles are listed below; only one role is permitted: .Pp When a role is not provided, the "value" role is used as the default. .Pp -Roles and modifiers can also use more verbose names, when preceeded by +Roles and modifiers can also use more verbose names, when preceded by a comma: .Bd -literal -offset indent EXAMPLE: @@ -380,7 +380,7 @@ The modifier string "Vkq" means the field has a value role, that it is a key for the current instance, and that the value should be quoted when encoded for JSON. .Pp -Roles and modifiers can also use more verbose names, when preceeded by +Roles and modifiers can also use more verbose names, when preceded by a comma. For example, the modifier string "Lwc" (or "L,white,colon") means the field has a label role (text that describes the next field) diff --git a/contrib/libxo/libxo/xo_syslog.c b/contrib/libxo/libxo/xo_syslog.c index da53e0c..c7d67f3 100644 --- a/contrib/libxo/libxo/xo_syslog.c +++ b/contrib/libxo/libxo/xo_syslog.c @@ -91,7 +91,7 @@ #elif defined(__macosx__) #define XO_DEFAULT_EID 63 #else -#define XO_DEFAULT_EID 32473 /* Bail; use "example" number */ +#define XO_DEFAULT_EID 32473 /* Fallback to the "example" number */ #endif #ifdef _SC_HOST_NAME_MAX diff --git a/contrib/libxo/tests/core/saved/test_03.E.out b/contrib/libxo/tests/core/saved/test_03.E.out index 3965783..c68081f 100644 --- a/contrib/libxo/tests/core/saved/test_03.E.out +++ b/contrib/libxo/tests/core/saved/test_03.E.out @@ -1,6 +1,18 @@ op create: [] [] op open_container: [employees] [] op open_list: [employee] [] +op close_list: [employee] [] +op string: [extra] [] +op open_list: [memory] [] +op open_instance: [memory] [] +op string: [type] [name] +op content: [in-use] [12345] +op content: [memory-use] [54321] +op string: [high-use] [-] +op content: [requests] [32145] +op close_instance: [memory] [] +op close_list: [memory] [] +op open_list: [employee] [] op open_instance: [employee] [] op string: [first-name] [Terry] op string: [last-name] [Jones] diff --git a/contrib/libxo/tests/core/saved/test_03.H.out b/contrib/libxo/tests/core/saved/test_03.H.out index 6b9ccc4..ff61897 100644 --- a/contrib/libxo/tests/core/saved/test_03.H.out +++ b/contrib/libxo/tests/core/saved/test_03.H.out @@ -1 +1 @@ -<div class="line"><div class="data" data-tag="first-name">Terry</div><div class="text"> </div><div class="data" data-tag="last-name">Jones</div><div class="text"> works in dept #</div><div class="data" data-tag="department">660</div></div><div class="line"><div class="data" data-tag="first-name">Leslie</div><div class="text"> </div><div class="data" data-tag="last-name">Patterson</div><div class="text"> works in dept #</div><div class="data" data-tag="department">341</div></div><div class="line"><div class="data" data-tag="first-name">Ashley</div><div class="text"> </div><div class="data" data-tag="last-name">Smith</div><div class="text"> works in dept #</div><div class="data" data-tag="department">1440</div></div>
\ No newline at end of file +<div class="line"><div class="text">[</div><div class="data" data-tag="extra"></div><div class="text">]</div></div><div class="line"><div class="title"> Type</div><div class="text"> </div><div class="title">InUse</div><div class="text"> </div><div class="title">MemUse</div><div class="text"> </div><div class="title">HighUse</div><div class="text"> </div><div class="title">Requests</div><div class="text"> </div><div class="title">Size(s)</div></div><div class="line"><div class="data" data-tag="type"> name</div><div class="text"> </div><div class="data" data-tag="in-use">12345</div><div class="text"> </div><div class="data" data-tag="memory-use">54321</div><div class="units">K</div><div class="text"> </div><div class="data" data-tag="high-use"> -</div><div class="text"> </div><div class="data" data-tag="requests"> 32145</div><div class="text"> </div></div><div class="line"><div class="data" data-tag="first-name">Terry</div><div class="text"> </div><div class="data" data-tag="last-name">Jones</div><div class="text"> works in dept #</div><div class="data" data-tag="department">660</div></div><div class="line"><div class="data" data-tag="first-name">Leslie</div><div class="text"> </div><div class="data" data-tag="last-name">Patterson</div><div class="text"> works in dept #</div><div class="data" data-tag="department">341</div></div><div class="line"><div class="data" data-tag="first-name">Ashley</div><div class="text"> </div><div class="data" data-tag="last-name">Smith</div><div class="text"> works in dept #</div><div class="data" data-tag="department">1440</div></div><div class="line"><div class="text">done</div></div>
\ No newline at end of file diff --git a/contrib/libxo/tests/core/saved/test_03.HIPx.out b/contrib/libxo/tests/core/saved/test_03.HIPx.out index bfae221..aaf867b 100644 --- a/contrib/libxo/tests/core/saved/test_03.HIPx.out +++ b/contrib/libxo/tests/core/saved/test_03.HIPx.out @@ -1,4 +1,35 @@ <div class="line"> + <div class="text">[</div> + <div class="data" data-tag="extra" data-xpath="/employees/extra"></div> + <div class="text">]</div> +</div> +<div class="line"> + <div class="title"> Type</div> + <div class="text"> </div> + <div class="title">InUse</div> + <div class="text"> </div> + <div class="title">MemUse</div> + <div class="text"> </div> + <div class="title">HighUse</div> + <div class="text"> </div> + <div class="title">Requests</div> + <div class="text"> </div> + <div class="title">Size(s)</div> +</div> +<div class="line"> + <div class="data" data-tag="type" data-xpath="/employees/memory/type"> name</div> + <div class="text"> </div> + <div class="data" data-tag="in-use" data-xpath="/employees/memory[type = 'name']/in-use">12345</div> + <div class="text"> </div> + <div class="data" data-tag="memory-use" data-xpath="/employees/memory[type = 'name']/memory-use">54321</div> + <div class="units">K</div> + <div class="text"> </div> + <div class="data" data-tag="high-use" data-xpath="/employees/memory[type = 'name']/high-use"> -</div> + <div class="text"> </div> + <div class="data" data-tag="requests" data-xpath="/employees/memory[type = 'name']/requests"> 32145</div> + <div class="text"> </div> +</div> +<div class="line"> <div class="data" data-tag="first-name" data-xpath="/employees/employee/first-name" data-type="string" data-help="First name of employee">Terry</div> <div class="text"> </div> <div class="data" data-tag="last-name" data-xpath="/employees/employee/last-name" data-type="string" data-help="Last name of employee">Jones</div> @@ -19,3 +50,6 @@ <div class="text"> works in dept #</div> <div class="data" data-tag="department" data-xpath="/employees/employee/department">1440</div> </div> +<div class="line"> + <div class="text">done</div> +</div> diff --git a/contrib/libxo/tests/core/saved/test_03.HP.out b/contrib/libxo/tests/core/saved/test_03.HP.out index f8b072a..2e476fb 100644 --- a/contrib/libxo/tests/core/saved/test_03.HP.out +++ b/contrib/libxo/tests/core/saved/test_03.HP.out @@ -1,4 +1,35 @@ <div class="line"> + <div class="text">[</div> + <div class="data" data-tag="extra"></div> + <div class="text">]</div> +</div> +<div class="line"> + <div class="title"> Type</div> + <div class="text"> </div> + <div class="title">InUse</div> + <div class="text"> </div> + <div class="title">MemUse</div> + <div class="text"> </div> + <div class="title">HighUse</div> + <div class="text"> </div> + <div class="title">Requests</div> + <div class="text"> </div> + <div class="title">Size(s)</div> +</div> +<div class="line"> + <div class="data" data-tag="type"> name</div> + <div class="text"> </div> + <div class="data" data-tag="in-use">12345</div> + <div class="text"> </div> + <div class="data" data-tag="memory-use">54321</div> + <div class="units">K</div> + <div class="text"> </div> + <div class="data" data-tag="high-use"> -</div> + <div class="text"> </div> + <div class="data" data-tag="requests"> 32145</div> + <div class="text"> </div> +</div> +<div class="line"> <div class="data" data-tag="first-name">Terry</div> <div class="text"> </div> <div class="data" data-tag="last-name">Jones</div> @@ -19,3 +50,6 @@ <div class="text"> works in dept #</div> <div class="data" data-tag="department">1440</div> </div> +<div class="line"> + <div class="text">done</div> +</div> diff --git a/contrib/libxo/tests/core/saved/test_03.J.out b/contrib/libxo/tests/core/saved/test_03.J.out index 4ba1fb1..00a5301 100644 --- a/contrib/libxo/tests/core/saved/test_03.J.out +++ b/contrib/libxo/tests/core/saved/test_03.J.out @@ -1,2 +1,2 @@ -{"employees": {"employee": [{"first-name":"Terry","last-name":"Jones","department":660}, {"first-name":"Leslie","last-name":"Patterson","department":341}, {"first-name":"Ashley","last-name":"Smith","department":1440}]} +{"employees": {"employee": [],"extra":"", "memory": [{"type":"name","in-use":12345,"memory-use":54321,"high-use":"-","requests":32145}], "employee": [{"first-name":"Terry","last-name":"Jones","department":660}, {"first-name":"Leslie","last-name":"Patterson","department":341}, {"first-name":"Ashley","last-name":"Smith","department":1440}]} } diff --git a/contrib/libxo/tests/core/saved/test_03.JP.out b/contrib/libxo/tests/core/saved/test_03.JP.out index ff2d5b0..a62f47e 100644 --- a/contrib/libxo/tests/core/saved/test_03.JP.out +++ b/contrib/libxo/tests/core/saved/test_03.JP.out @@ -1,6 +1,18 @@ { "employees": { "employee": [ + ], + "extra": "", + "memory": [ + { + "type": "name", + "in-use": 12345, + "memory-use": 54321, + "high-use": "-", + "requests": 32145 + } + ], + "employee": [ { "first-name": "Terry", "last-name": "Jones", diff --git a/contrib/libxo/tests/core/saved/test_03.T.out b/contrib/libxo/tests/core/saved/test_03.T.out index da60fb7..90486fb 100644 --- a/contrib/libxo/tests/core/saved/test_03.T.out +++ b/contrib/libxo/tests/core/saved/test_03.T.out @@ -1,3 +1,7 @@ +[] + Type InUse MemUse HighUse Requests Size(s) + name 12345 54321K - 32145 Terry Jones works in dept #660 Leslie Patterson works in dept #341 Ashley Smith works in dept #1440 +done diff --git a/contrib/libxo/tests/core/saved/test_03.X.out b/contrib/libxo/tests/core/saved/test_03.X.out index a626fb6..279e359 100644 --- a/contrib/libxo/tests/core/saved/test_03.X.out +++ b/contrib/libxo/tests/core/saved/test_03.X.out @@ -1 +1 @@ -<employees><employee><first-name>Terry</first-name><last-name>Jones</last-name><department>660</department></employee><employee><first-name>Leslie</first-name><last-name>Patterson</last-name><department>341</department></employee><employee><first-name>Ashley</first-name><last-name>Smith</last-name><department>1440</department></employee></employees>
\ No newline at end of file +<employees><extra></extra><memory><type>name</type><in-use>12345</in-use><memory-use>54321</memory-use><high-use>-</high-use><requests>32145</requests></memory><employee><first-name>Terry</first-name><last-name>Jones</last-name><department>660</department></employee><employee><first-name>Leslie</first-name><last-name>Patterson</last-name><department>341</department></employee><employee><first-name>Ashley</first-name><last-name>Smith</last-name><department>1440</department></employee></employees>
\ No newline at end of file diff --git a/contrib/libxo/tests/core/saved/test_03.XP.out b/contrib/libxo/tests/core/saved/test_03.XP.out index b6e7641..751bbfc 100644 --- a/contrib/libxo/tests/core/saved/test_03.XP.out +++ b/contrib/libxo/tests/core/saved/test_03.XP.out @@ -1,4 +1,12 @@ <employees> + <extra></extra> + <memory> + <type>name</type> + <in-use>12345</in-use> + <memory-use>54321</memory-use> + <high-use>-</high-use> + <requests>32145</requests> + </memory> <employee> <first-name>Terry</first-name> <last-name>Jones</last-name> diff --git a/contrib/libxo/tests/core/test_03.c b/contrib/libxo/tests/core/test_03.c index 0ab9699..af65ddd 100644 --- a/contrib/libxo/tests/core/test_03.c +++ b/contrib/libxo/tests/core/test_03.c @@ -25,6 +25,9 @@ int info_count = (sizeof(info) / sizeof(info[0])); int main (int argc, char **argv) { + unsigned opt_count = 1; + unsigned opt_extra = 0; + struct employee { const char *e_first; const char *e_last; @@ -34,24 +37,68 @@ main (int argc, char **argv) { "Leslie", "Patterson", 341 }, { "Ashley", "Smith", 1440 }, { NULL, NULL } - }, *ep = employees; + }, *ep; argc = xo_parse_args(argc, argv); if (argc < 0) return 1; + for (argc = 1; argv[argc]; argc++) { + if (strcmp(argv[argc], "count") == 0) { + if (argv[argc + 1]) + opt_count = atoi(argv[++argc]); + } else if (strcmp(argv[argc], "extra") == 0) { + if (argv[argc + 1]) + opt_extra = atoi(argv[++argc]); + } + } + xo_set_info(NULL, info, info_count); xo_open_container("employees"); xo_open_list("employee"); - for ( ; ep->e_first; ep++) { - xo_open_instance("employee"); - xo_emit("{:first-name} {:last-name} works in dept #{:department/%u}\n", - ep->e_first, ep->e_last, ep->e_dept); - xo_close_instance("employee"); + xo_emit("[{:extra/%*s}]\n", opt_extra, ""); + + xo_emit("{T:/%13s} {T:/%5s} {T:/%6s} {T:/%7s} {T:/%8s} {T:Size(s)}\n", + "Type", "InUse", "MemUse", "HighUse", "Requests"); + xo_open_list("memory"); + xo_open_instance("memory"); + +#define PRIu64 "llu" +#define TO_ULL(_x) ((unsigned long long) _x) + xo_emit("{k:type/%13s} {:in-use/%5" PRIu64 "} " + "{:memory-use/%5" PRIu64 "}{U:K} {:high-use/%7s} " + "{:requests/%8" PRIu64 "} ", + "name", TO_ULL(12345), TO_ULL(54321), "-", TO_ULL(32145)); + + int first = 1, i; +#if 0 + xo_open_list("size"); + for (i = 0; i < 32; i++) { + if (!first) + xo_emit(","); + xo_emit("{l:size/%d}", 1 << (i + 4)); + first = 0; + } + xo_close_list("size"); +#endif + xo_close_instance("memory"); + xo_emit("\n"); + xo_close_list("memory"); + + while (opt_count-- != 0) { + for (ep = employees; ep->e_first; ep++) { + xo_open_instance("employee"); + xo_emit("{:first-name} {:last-name} works in " + "dept #{:department/%u}\n", + ep->e_first, ep->e_last, ep->e_dept); + xo_close_instance("employee"); + } } + xo_emit("done\n"); + xo_close_list("employee"); xo_close_container("employees"); diff --git a/contrib/llvm/lib/Target/X86/X86ISelLowering.cpp b/contrib/llvm/lib/Target/X86/X86ISelLowering.cpp index 25288a7..66b12d3 100644 --- a/contrib/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/contrib/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -26159,6 +26159,8 @@ static SDValue detectAVGPattern(SDValue In, EVT VT, SelectionDAG &DAG, if (InScalarVT.getSizeInBits() <= ScalarVT.getSizeInBits()) return SDValue(); + if (!Subtarget->hasSSE2()) + return SDValue(); if (Subtarget->hasAVX512()) { if (VT.getSizeInBits() > 512) return SDValue(); diff --git a/contrib/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/contrib/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index 17c25df..2935460 100644 --- a/contrib/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/contrib/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -3161,10 +3161,11 @@ void InnerLoopVectorizer::truncateToMinimalBitwidths() { // truncated version of `I` and reextend its result. InstCombine runs // later and will remove any ext/trunc pairs. // + SmallPtrSet<Value *, 4> Erased; for (auto &KV : MinBWs) { VectorParts &Parts = WidenMap.get(KV.first); for (Value *&I : Parts) { - if (I->use_empty()) + if (Erased.count(I) || I->use_empty()) continue; Type *OriginalTy = I->getType(); Type *ScalarTruncatedTy = IntegerType::get(OriginalTy->getContext(), @@ -3238,6 +3239,7 @@ void InnerLoopVectorizer::truncateToMinimalBitwidths() { Value *Res = B.CreateZExtOrTrunc(NewI, OriginalTy); I->replaceAllUsesWith(Res); cast<Instruction>(I)->eraseFromParent(); + Erased.insert(I); I = Res; } } |