diff --git a/20160409/Makefile b/20160409/Makefile new file mode 100644 index 000000000000..da4411d0ca75 --- /dev/null +++ b/20160409/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 diff --git a/20160409/Makefile.inc b/20160409/Makefile.inc new file mode 100644 index 000000000000..85c82783cd35 --- /dev/null +++ b/20160409/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/20160409/README b/20160409/README new file mode 100644 index 000000000000..44e1026ac4db --- /dev/null +++ b/20160409/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/20160409/TODO b/20160409/TODO new file mode 100644 index 000000000000..9925020d54bb --- /dev/null +++ b/20160409/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? + ? 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/20160409/bin/Makefile b/20160409/bin/Makefile new file mode 100644 index 000000000000..280c72fd3af1 --- /dev/null +++ b/20160409/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 diff --git a/20160409/bin/blacklistctl.8 b/20160409/bin/blacklistctl.8 new file mode 100644 index 000000000000..d8ed1f09cde2 --- /dev/null +++ b/20160409/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/20160409/bin/blacklistctl.c b/20160409/bin/blacklistctl.c new file mode 100644 index 000000000000..d202fb159b89 --- /dev/null +++ b/20160409/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 +__RCSID("$NetBSD: blacklistctl.c,v 1.20 2016/04/04 15:52:56 christos Exp $"); + +#include +#include +#ifdef HAVE_LIBUTIL_H +#include +#endif +#ifdef HAVE_UTIL_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#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/20160409/bin/blacklistd.8 b/20160409/bin/blacklistd.8 new file mode 100644 index 000000000000..ae684770357f --- /dev/null +++ b/20160409/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
+.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
+.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 /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 +.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 /libexec/blacklistd-helper -compact +.It Pa /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/20160409/bin/blacklistd.c b/20160409/bin/blacklistd.c new file mode 100644 index 000000000000..c16b18e193a5 --- /dev/null +++ b/20160409/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 +__RCSID("$NetBSD: blacklistd.c,v 1.34 2016/04/04 15:52:56 christos Exp $"); + +#include +#include +#include + +#ifdef HAVE_LIBUTIL_H +#include +#endif +#ifdef HAVE_UTIL_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ] [-R ] " + "[-P ] [-C ] [-D ] " + "[-s ] [-t ]\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/20160409/bin/blacklistd.conf.5 b/20160409/bin/blacklistd.conf.5 new file mode 100644 index 000000000000..40d507b3c08a --- /dev/null +++ b/20160409/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 + [
|][/][:] +.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/20160409/bin/conf.c b/20160409/bin/conf.c new file mode 100644 index 000000000000..3ec1e085c276 --- /dev/null +++ b/20160409/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 +__RCSID("$NetBSD: conf.c,v 1.24 2016/04/04 15:52:56 christos Exp $"); + +#include +#ifdef HAVE_LIBUTIL_H +#include +#endif +#ifdef HAVE_UTIL_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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/20160409/bin/conf.h b/20160409/bin/conf.h new file mode 100644 index 000000000000..03f1942e3e32 --- /dev/null +++ b/20160409/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 + +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/20160409/bin/internal.c b/20160409/bin/internal.c new file mode 100644 index 000000000000..5c039e4dc5d2 --- /dev/null +++ b/20160409/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 +__RCSID("$NetBSD: internal.c,v 1.5 2015/01/27 19:40:37 christos Exp $"); + +#include +#include +#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/20160409/bin/internal.h b/20160409/bin/internal.h new file mode 100644 index 000000000000..5a40e49fbbd5 --- /dev/null +++ b/20160409/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/20160409/bin/run.c b/20160409/bin/run.c new file mode 100644 index 000000000000..8499edd3d9c2 --- /dev/null +++ b/20160409/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 +__RCSID("$NetBSD: run.c,v 1.14 2016/04/04 15:52:56 christos Exp $"); + +#include +#ifdef HAVE_LIBUTIL_H +#include +#endif +#ifdef HAVE_UTIL_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#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/20160409/bin/run.h b/20160409/bin/run.h new file mode 100644 index 000000000000..bafc3e554690 --- /dev/null +++ b/20160409/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/20160409/bin/state.c b/20160409/bin/state.c new file mode 100644 index 000000000000..eb97e970fb1e --- /dev/null +++ b/20160409/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 +__RCSID("$NetBSD: state.c,v 1.18 2016/04/04 15:52:56 christos Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#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/20160409/bin/state.h b/20160409/bin/state.h new file mode 100644 index 000000000000..2e9257006e80 --- /dev/null +++ b/20160409/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 +#elif HAVE_DB_H +#include +#else +#error "no db.h" +#endif +#include + +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/20160409/bin/support.c b/20160409/bin/support.c new file mode 100644 index 000000000000..0dac499aca02 --- /dev/null +++ b/20160409/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 +__RCSID("$NetBSD: support.c,v 1.8 2016/04/04 15:52:56 christos Exp $"); + +#include +#include +#include +#include +#include +#include +#include + +#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/20160409/bin/support.h b/20160409/bin/support.h new file mode 100644 index 000000000000..899649ce8319 --- /dev/null +++ b/20160409/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/20160409/diff/ftpd.diff b/20160409/diff/ftpd.diff new file mode 100644 index 000000000000..d28577f3ef5f --- /dev/null +++ b/20160409/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 ++#include ++ ++#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 + #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/20160409/diff/named.diff b/20160409/diff/named.diff new file mode 100644 index 000000000000..fcd97ba7ec1f --- /dev/null +++ b/20160409/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 ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#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 +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 + #include + ++#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 + #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 + #include + ++#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 + #include + ++#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 + #include + ++#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/20160409/diff/proftpd.diff b/20160409/diff/proftpd.diff new file mode 100644 index 000000000000..c811c9cf50bc --- /dev/null +++ b/20160409/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 ++#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/20160409/diff/ssh.diff b/20160409/diff/ssh.diff new file mode 100644 index 000000000000..bc0b75c05674 --- /dev/null +++ b/20160409/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 ++ ++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 +@@ -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 +@@ -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/20160409/etc/Makefile b/20160409/etc/Makefile new file mode 100644 index 000000000000..669528ddca89 --- /dev/null +++ b/20160409/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 +.include diff --git a/20160409/etc/blacklistd.conf b/20160409/etc/blacklistd.conf new file mode 100644 index 000000000000..f061b004ad36 --- /dev/null +++ b/20160409/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/20160409/etc/npf.conf b/20160409/etc/npf.conf new file mode 100644 index 000000000000..42d56044ad6e --- /dev/null +++ b/20160409/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/20160409/etc/rc.d/Makefile b/20160409/etc/rc.d/Makefile new file mode 100644 index 000000000000..e863d0853a0f --- /dev/null +++ b/20160409/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 diff --git a/20160409/etc/rc.d/blacklistd b/20160409/etc/rc.d/blacklistd new file mode 100644 index 000000000000..2e46f518fc70 --- /dev/null +++ b/20160409/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/20160409/include/Makefile b/20160409/include/Makefile new file mode 100644 index 000000000000..6854907be25e --- /dev/null +++ b/20160409/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 diff --git a/20160409/include/bl.h b/20160409/include/bl.h new file mode 100644 index 000000000000..68249cdf8230 --- /dev/null +++ b/20160409/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 +#include +#include +#include +#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/20160409/include/blacklist.h b/20160409/include/blacklist.h new file mode 100644 index 000000000000..9ebe11b95e08 --- /dev/null +++ b/20160409/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 + +__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/20160409/lib/Makefile b/20160409/lib/Makefile new file mode 100644 index 000000000000..aea01caca228 --- /dev/null +++ b/20160409/lib/Makefile @@ -0,0 +1,19 @@ +# $NetBSD: Makefile,v 1.6 2016/01/05 13:07:46 christos Exp $ + +.include + +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 diff --git a/20160409/lib/bl.c b/20160409/lib/bl.c new file mode 100644 index 000000000000..bca52cfbc8fe --- /dev/null +++ b/20160409/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 +__RCSID("$NetBSD: bl.c,v 1.27 2015/12/30 16:42:48 christos Exp $"); + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _REENTRANT +#include +#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/20160409/lib/blacklist.c b/20160409/lib/blacklist.c new file mode 100644 index 000000000000..b8a524ca301a --- /dev/null +++ b/20160409/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 +__RCSID("$NetBSD: blacklist.c,v 1.5 2015/01/22 16:19:53 christos Exp $"); + +#include +#include + +#include +#include +#include +#include +#include + +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/20160409/lib/libblacklist.3 b/20160409/lib/libblacklist.3 new file mode 100644 index 000000000000..e13682031b81 --- /dev/null +++ b/20160409/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/20160409/lib/shlib_version b/20160409/lib/shlib_version new file mode 100644 index 000000000000..97c9f92d6b8f --- /dev/null +++ b/20160409/lib/shlib_version @@ -0,0 +1,2 @@ +major=0 +minor=0 diff --git a/20160409/libexec/Makefile b/20160409/libexec/Makefile new file mode 100644 index 000000000000..6537080bf465 --- /dev/null +++ b/20160409/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 diff --git a/20160409/libexec/blacklistd-helper b/20160409/libexec/blacklistd-helper new file mode 100644 index 000000000000..743ccf5508b3 --- /dev/null +++ b/20160409/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 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/20160409/port/Makefile.am b/20160409/port/Makefile.am new file mode 100644 index 000000000000..f1b36ca880a3 --- /dev/null +++ b/20160409/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/20160409/port/_strtoi.h b/20160409/port/_strtoi.h new file mode 100644 index 000000000000..4b2b4e80f0d8 --- /dev/null +++ b/20160409/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/20160409/port/clock_gettime.c b/20160409/port/clock_gettime.c new file mode 100644 index 000000000000..284bd8176901 --- /dev/null +++ b/20160409/port/clock_gettime.c @@ -0,0 +1,17 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +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/20160409/port/config.h b/20160409/port/config.h new file mode 100644 index 000000000000..27f32636de01 --- /dev/null +++ b/20160409/port/config.h @@ -0,0 +1,3 @@ +#if defined(__FreeBSD__) +#include "port.h" +#endif diff --git a/20160409/port/configure.ac b/20160409/port/configure.ac new file mode 100644 index 000000000000..eef8065f060a --- /dev/null +++ b/20160409/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 ]) + +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/20160409/port/fgetln.c b/20160409/port/fgetln.c new file mode 100644 index 000000000000..a41a383a6653 --- /dev/null +++ b/20160409/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 +#ifndef HAVE_NBTOOL_CONFIG_H +/* These headers are required, but included from nbtool_config.h */ +#include +#include +#include +#include +#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/20160409/port/fparseln.c b/20160409/port/fparseln.c new file mode 100644 index 000000000000..5bfae54b9a9b --- /dev/null +++ b/20160409/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 +#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 +#include +#include +#include +#include + +#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/20160409/port/getprogname.c b/20160409/port/getprogname.c new file mode 100644 index 000000000000..983d6740c88c --- /dev/null +++ b/20160409/port/getprogname.c @@ -0,0 +1,24 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include + +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/20160409/port/m4/.cvsignore b/20160409/port/m4/.cvsignore new file mode 100644 index 000000000000..0f4126cd6718 --- /dev/null +++ b/20160409/port/m4/.cvsignore @@ -0,0 +1 @@ +*.m4 diff --git a/20160409/port/pidfile.c b/20160409/port/pidfile.c new file mode 100644 index 000000000000..4deb2349d20a --- /dev/null +++ b/20160409/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 +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: pidfile.c,v 1.2 2016/04/05 12:28:57 christos Exp $"); +#endif + +#include + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LIBUTIL_H +#include +#endif +#ifdef HAVE_UTIL_H +#include +#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/20160409/port/popenve.c b/20160409/port/popenve.c new file mode 100644 index 000000000000..20f6b5b86b68 --- /dev/null +++ b/20160409/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 +#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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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/20160409/port/port.h b/20160409/port/port.h new file mode 100644 index 000000000000..f82fb34b40f5 --- /dev/null +++ b/20160409/port/port.h @@ -0,0 +1,86 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include + +#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/20160409/port/sockaddr_snprintf.c b/20160409/port/sockaddr_snprintf.c new file mode 100644 index 000000000000..41e5e0c0ed20 --- /dev/null +++ b/20160409/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 +#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 +#include +#include +#include + +#include +#ifdef __linux__ +#undef HAVE_NETATALK_AT_H +#endif +#ifdef HAVE_NETATALK_AT_H +#include +#endif +#ifdef HAVE_NET_IF_DL_H +#include +#endif + +#include +#include +#include +#include +#ifdef HAVE_LIBUTIL_H +#include +#endif +#ifdef HAVE_UTIL_H +#include +#endif +#include + +#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/20160409/port/strlcat.c b/20160409/port/strlcat.c new file mode 100644 index 000000000000..d3c69b5fab78 --- /dev/null +++ b/20160409/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 + * + * 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 +#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 +#include +#include + +#ifdef _LIBC +# ifdef __weak_alias +__weak_alias(strlcat, _strlcat) +# endif +#endif + +#else +#include +#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/20160409/port/strlcpy.c b/20160409/port/strlcpy.c new file mode 100644 index 000000000000..6646e1ce9696 --- /dev/null +++ b/20160409/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 + * + * 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 +#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 +#include +#include + +#ifdef _LIBC +# ifdef __weak_alias +__weak_alias(strlcpy, _strlcpy) +# endif +#endif +#else +#include +#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/20160409/port/strtoi.c b/20160409/port/strtoi.c new file mode 100644 index 000000000000..5514f1a00a32 --- /dev/null +++ b/20160409/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 +__RCSID("$NetBSD: strtoi.c,v 1.3 2015/01/22 03:10:50 christos Exp $"); + +#if defined(_KERNEL) +#include +#include +#include +#elif defined(_STANDALONE) +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif + +#define _FUNCNAME strtoi +#define __TYPE intmax_t +#define __WRAPPED strtoimax + +#if !HAVE_STRTOI +#include "_strtoi.h" +#endif diff --git a/20160409/test/Makefile b/20160409/test/Makefile new file mode 100644 index 000000000000..a451274def06 --- /dev/null +++ b/20160409/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 diff --git a/20160409/test/cltest.c b/20160409/test/cltest.c new file mode 100644 index 000000000000..6671429fc3c4 --- /dev/null +++ b/20160409/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 +__RCSID("$NetBSD: cltest.c,v 1.6 2015/01/22 05:44:28 christos Exp $"); + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef HAVE_UTIL_H +#include +#endif + +static __dead void +usage(int c) +{ + warnx("Unknown option `%c'", (char)c); + fprintf(stderr, "Usage: %s [-u] [-a ] [-m ] [-p ]\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/20160409/test/srvtest.c b/20160409/test/srvtest.c new file mode 100644 index 000000000000..03a762ab81f2 --- /dev/null +++ b/20160409/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 +__RCSID("$NetBSD: srvtest.c,v 1.10 2015/05/30 22:40:38 christos Exp $"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ]\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); + } + } +}