components/ftp-proxy/patches/001-solaris.patch
changeset 5565 f678cc44b3d0
child 7791 95f8368a21ec
equal deleted inserted replaced
5564:e533d5840fdd 5565:f678cc44b3d0
       
     1 # This patch comes from Oracle. It fixes issues preventing ftp-proxy
       
     2 # from building and running on Solaris. Especially, we:
       
     3 # - disabled features missing support on Solaris (queuing, rtable..)
       
     4 #   where adding such support is not reasonable
       
     5 # - used workarounds to deal with missing pieces on Solaris (missing
       
     6 #   structure members in sockaddr, PF not supporting divert-to,
       
     7 #   using Solaris-specific random number generator) 
       
     8 #
       
     9 # These changes are not going to upstream, they are Solaris-specific.
       
    10 
       
    11 diff -Naur ORIGINAL/Makefile ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/Makefile
       
    12 --- ORIGINAL/Makefile	2006-11-26 03:31:13.000000000 -0800
       
    13 +++ ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/Makefile	2016-02-10 04:21:21.337202150 -0800
       
    14 @@ -1,13 +1,29 @@
       
    15  #	$OpenBSD: Makefile,v 1.3 2006/11/26 11:31:13 deraadt Exp $
       
    16  
       
    17 +CFLAGS+= -m64 -errwarn
       
    18 +
       
    19  PROG=	ftp-proxy
       
    20  SRCS=	ftp-proxy.c filter.c
       
    21 +OBJS=$(SRCS:.c=.o)
       
    22  MAN=	ftp-proxy.8
       
    23  
       
    24 -CFLAGS+= -I${.CURDIR}
       
    25 -CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith \
       
    26 -         -Wno-uninitialized
       
    27 -LDADD+=	-levent
       
    28 -DPADD+= ${LIBEVENT}
       
    29 +LDADD+=	-levent -luutil
       
    30 +LDFLAGS+=	-z nolazyload
       
    31 +
       
    32 +all:	$(SRCS) $(PROG)
       
    33 +
       
    34 +install: $(PROG)
       
    35 +	$(INSTALL) -d $(PREFIX)/sbin
       
    36 +	$(INSTALL) -m 755 $(PROG) $(PREFIX)/sbin
       
    37 +	$(INSTALL) -d $(MANDIR)/man8
       
    38 +	$(INSTALL) -m 644 $(MAN) $(MANDIR)/man8
       
    39 +
       
    40 +$(PROG):	$(OBJS)
       
    41 +	$(CC) $(CFLAGS) $(OBJS) -o $@ $(LDFLAGS) $(LDADD)
       
    42 +
       
    43 +.c.o:
       
    44 +	$(CC) $(CFLAGS) -c -o $@ $<
       
    45  
       
    46 -.include <bsd.prog.mk>
       
    47 +clean:
       
    48 +	rm -rf *.o
       
    49 +	rm -rf $(PROG)
       
    50 diff -Naur ORIGINAL/filter.c ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/filter.c
       
    51 --- ORIGINAL/filter.c	2012-09-18 03:11:53.000000000 -0700
       
    52 +++ ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/filter.c	2016-02-10 04:24:03.599069704 -0800
       
    53 @@ -32,6 +32,10 @@
       
    54  #include <stdio.h>
       
    55  #include <string.h>
       
    56  #include <unistd.h>
       
    57 +#ifdef _SOLARIS_
       
    58 +/* we need _IOWR */
       
    59 +#include <sys/ioccom.h>
       
    60 +#endif	/* _SOLARIS_ */
       
    61  
       
    62  #include "filter.h"
       
    63  
       
    64 diff -Naur ORIGINAL/ftp-proxy.8 ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/ftp-proxy.8
       
    65 --- ORIGINAL/ftp-proxy.8	2012-06-25 04:49:19.000000000 -0700
       
    66 +++ ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/ftp-proxy.8	2016-02-24 06:31:17.792565815 -0800
       
    67 @@ -30,17 +30,16 @@
       
    68  .Op Fl m Ar maxsessions
       
    69  .Op Fl P Ar port
       
    70  .Op Fl p Ar port
       
    71 -.Op Fl q Ar queue
       
    72  .Op Fl R Ar address
       
    73  .Op Fl T Ar tag
       
    74  .Op Fl t Ar timeout
       
    75  .Ek
       
    76  .Sh DESCRIPTION
       
    77  .Nm
       
    78 -is a proxy for the Internet File Transfer Protocol.
       
    79 -FTP control connections should be redirected into the proxy using the
       
    80 -.Xr pf 4
       
    81 -.Ar divert-to
       
    82 +is a proxy for the Internet File Transfer Protocol making connections
       
    83 +over IPv4 NAT possible.
       
    84 +FTP control connections should be redirected into the proxy using the PF
       
    85 +.Ar rdr-to
       
    86  command, after which the proxy connects to the server on behalf of
       
    87  the client.
       
    88  .Pp
       
    89 @@ -51,22 +50,20 @@
       
    90  Consequently, all connections from the server to the proxy have
       
    91  their destination address rewritten, so they are redirected to the
       
    92  client.
       
    93 -The proxy uses the
       
    94 -.Xr pf 4
       
    95 +The proxy uses the PF
       
    96  .Ar anchor
       
    97  facility for this.
       
    98  .Pp
       
    99  Assuming the FTP control connection is from $client to $server, the
       
   100 -proxy connected to the server using the $proxy source address, and
       
   101 -$port is negotiated, then
       
   102 +proxy is connected to the server using the $proxy source address, and
       
   103 +$port is negotiated, the
       
   104  .Nm
       
   105  adds the following rules to the anchor.
       
   106  $server and $orig_server are the same unless
       
   107  .Fl R
       
   108  is used to force a different $server address for all connections.
       
   109 -(These example rules use inet, but the proxy also supports inet6.)
       
   110  .Pp
       
   111 -In case of active mode (PORT or EPRT):
       
   112 +In case of active mode (PORT):
       
   113  .Bd -literal -offset 2n
       
   114  pass in from $server to $proxy port $proxy_port \e
       
   115      rdr-to $client port $port
       
   116 @@ -74,7 +71,7 @@
       
   117      nat-to $orig_server port $natport
       
   118  .Ed
       
   119  .Pp
       
   120 -In case of passive mode (PASV or EPSV):
       
   121 +In case of passive mode (PASV):
       
   122  .Bd -literal -offset 2n
       
   123  pass in from $client to $orig_server port $proxy_port \e
       
   124      rdr-to $server port $port
       
   125 @@ -83,11 +80,6 @@
       
   126  .Pp
       
   127  The options are as follows:
       
   128  .Bl -tag -width Ds
       
   129 -.It Fl 6
       
   130 -IPv6 mode.
       
   131 -The proxy will expect and use IPv6 addresses for all communication.
       
   132 -Only the extended FTP modes EPSV and EPRT are allowed with IPv6.
       
   133 -The proxy is in IPv4 mode by default.
       
   134  .It Fl A
       
   135  Only permit anonymous FTP connections.
       
   136  Either user "ftp" or user "anonymous" is allowed.
       
   137 @@ -96,14 +88,11 @@
       
   138  connection to a server.
       
   139  .It Fl b Ar address
       
   140  Address where the proxy will listen for redirected control connections.
       
   141 -The default is 127.0.0.1, or ::1 in IPv6 mode.
       
   142 +The default is 127.0.0.1.
       
   143  .It Fl D Ar level
       
   144  Debug level, ranging from 0 to 7.
       
   145  Higher is more verbose.
       
   146  The default is 5.
       
   147 -(These levels correspond to the
       
   148 -.Xr syslog 3
       
   149 -levels.)
       
   150  .It Fl d
       
   151  Do not daemonize.
       
   152  The process will stay in the foreground, logging to standard error.
       
   153 @@ -120,10 +109,6 @@
       
   154  .It Fl p Ar port
       
   155  Port where the proxy will listen for redirected connections.
       
   156  The default is port 8021.
       
   157 -.It Fl q Ar queue
       
   158 -Create rules with queue
       
   159 -.Ar queue
       
   160 -appended, so that data connections can be queued.
       
   161  .It Fl R Ar address
       
   162  Fixed server address, also known as reverse mode.
       
   163  The proxy will always connect to the same server, regardless of
       
   164 @@ -142,9 +127,8 @@
       
   165  keyword can be implemented following the
       
   166  .Nm
       
   167  anchor.
       
   168 -These rules can use special
       
   169 -.Xr pf 4
       
   170 -features like route-to, reply-to, label, rtable, overload, etc. that
       
   171 +These rules can use special PF
       
   172 +features like route-to, reply-to, label, overload, etc. that
       
   173  .Nm
       
   174  does not implement itself.
       
   175  There must be a matching pass rule after the
       
   176 @@ -159,7 +143,9 @@
       
   177  .It Fl v
       
   178  Set the 'log' flag on pf rules committed by
       
   179  .Nm .
       
   180 -Use twice to set the 'log all' flag.
       
   181 +Use twice to set the
       
   182 +.Sq log all
       
   183 +flag.
       
   184  The pf rules do not log by default.
       
   185  .El
       
   186  .Sh CONFIGURATION
       
   187 @@ -171,27 +157,23 @@
       
   188  necessary.
       
   189  .Bd -literal -offset 2n
       
   190  anchor "ftp-proxy/*"
       
   191 -pass in quick inet proto tcp to port ftp divert-to 127.0.0.1 port 8021
       
   192 +pass in quick inet proto tcp to port ftp rdr-to 127.0.0.1 port 8021
       
   193  pass out inet proto tcp from (self) to any port ftp
       
   194  .Ed
       
   195 +.Pp
       
   196 +To run
       
   197 +.Nm
       
   198 +in a non-global zone, the
       
   199 +.Bd -literal -offset indent
       
   200 +svc:/network/socket-filter:pf_divert
       
   201 +.Ed
       
   202 +instance must be online in the global zone.
       
   203  .Sh SEE ALSO
       
   204 -.Xr ftp 1 ,
       
   205 -.Xr pf 4 ,
       
   206  .Xr pf.conf 5
       
   207  .Sh CAVEATS
       
   208 -.Xr pf 4
       
   209 -does not allow the ruleset to be modified if the system is running at a
       
   210 -.Xr securelevel 7
       
   211 -higher than 1.
       
   212 -At that level
       
   213 -.Nm
       
   214 -cannot add rules to the anchors and FTP data connections may get blocked.
       
   215  .Pp
       
   216  Negotiated data connection ports below 1024 are not allowed.
       
   217  .Pp
       
   218  The negotiated IP address for active modes is ignored for security
       
   219  reasons.
       
   220  This makes third party file transfers impossible.
       
   221 -.Pp
       
   222 -.Nm
       
   223 -chroots to "/var/empty" and changes to user "proxy" to drop privileges.
       
   224 diff -Naur ORIGINAL/ftp-proxy.c ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/ftp-proxy.c
       
   225 --- ORIGINAL/ftp-proxy.c	2013-03-15 06:31:27.000000000 -0700
       
   226 +++ ftp-proxy-OPENBSD_5_5-OPENBSD_5_5.pre-smf/ftp-proxy.c	2016-02-10 04:12:16.600723376 -0800
       
   227 @@ -38,9 +38,20 @@
       
   228  #include <stdio.h>
       
   229  #include <stdlib.h>
       
   230  #include <string.h>
       
   231 +#ifdef _SOLARIS_
       
   232 +#include <strings.h>
       
   233 +#include <sys/types.h>
       
   234 +#include <time.h>
       
   235 +#include <libuutil.h>
       
   236 +#include <sys/random.h>
       
   237 +#include <inttypes.h>
       
   238 +#include <priv.h>
       
   239 +#endif	/* _SOLARIS_ */
       
   240  #include <syslog.h>
       
   241  #include <unistd.h>
       
   242 +#ifndef _SOLARIS_
       
   243  #include <vis.h>
       
   244 +#endif	/* !_SOLARIS_ */
       
   245  
       
   246  #include "filter.h"
       
   247  
       
   248 @@ -60,6 +71,32 @@
       
   249  
       
   250  #define	sstosa(ss)	((struct sockaddr *)(ss))
       
   251  
       
   252 +#ifdef _SOLARIS_
       
   253 +/*
       
   254 + * These constants are used as a range used by pick_proxy_port(). The ftp-proxy
       
   255 + * never binds these ports. They are used only within proxy_reply() and add_rdr()
       
   256 + * to be put into a FTP-protocol message and to construct the rule to be loaded
       
   257 + * into PF, respectively.
       
   258 + *
       
   259 + * OpenBSD adheres to a convention where these port numbers are reserved for
       
   260 + * connections that want to bypass a firewall. Surely, it depends on how the
       
   261 + * administrator configures the firewall, too. Let's stick to that convention
       
   262 + * here. The idea probably is "if the admin uses this convention, these ports
       
   263 + * are not filtered and thus we are not going to clash with current firewall
       
   264 + * rules".
       
   265 + */
       
   266 +#define IPPORT_HIFIRSTAUTO	49152
       
   267 +#define IPPORT_HILASTAUTO	65535
       
   268 +
       
   269 +#define getrtable() 0
       
   270 +
       
   271 +#ifndef LIST_END
       
   272 +#define LIST_END(x) NULL
       
   273 +#endif	/* !LIST_END */
       
   274 +
       
   275 +#define	DIVERT_MODULE_NAME "pf_divertf"
       
   276 +#endif	/* _SOLARIS_ */
       
   277 +
       
   278  enum { CMD_NONE = 0, CMD_PORT, CMD_EPRT, CMD_PASV, CMD_EPSV };
       
   279  
       
   280  struct session {
       
   281 @@ -115,12 +152,59 @@
       
   282  
       
   283  struct event listen_ev, pause_accept_ev;
       
   284  struct sockaddr_storage fixed_server_ss, fixed_proxy_ss;
       
   285 +#ifdef _SOLARIS_
       
   286 +static socklen_t fixed_server_ss_len;
       
   287 +static socklen_t fixed_proxy_ss_len;
       
   288 +#endif	/* _SOLARIS_ */
       
   289  char *fixed_server, *fixed_server_port, *fixed_proxy, *listen_ip, *listen_port,
       
   290      *qname, *tagname;
       
   291  int anonymous_only, daemonize, id_count, ipv6_mode, loglevel, max_sessions,
       
   292      rfc_mode, session_count, timeout, verbose;
       
   293  extern char *__progname;
       
   294  
       
   295 +#ifdef	_SOLARIS_
       
   296 +/*
       
   297 + * fake_arc4random_uniform()
       
   298 + * This is a fake implementation of arc4random_uniform(). The wrapper
       
   299 + * provides so called uniform calculation of pseudo random number with
       
   300 + * respect to upper bound.
       
   301 + *
       
   302 + * Function calculates random numbers until it finds one outside
       
   303 + * <0, 2^32 % upper_bound) range. Once random number, `rand`, is selected,
       
   304 + * function returns rand % upper_bound.
       
   305 + *
       
   306 + * Arguments:
       
   307 + *	upper_bound	- random number is picked up in range <0, upper_bound)
       
   308 + *
       
   309 + * Returns:
       
   310 + *	random number, uniform with respect to upper bound.
       
   311 + *      Returns UINT32_MAX on error.
       
   312 + */
       
   313 +static u_int32_t
       
   314 +fake_arc4random_uniform(u_int32_t upper_bound)
       
   315 +{
       
   316 +	u_int32_t	rand, min;
       
   317 +
       
   318 +	if (upper_bound < 2)
       
   319 +		return (0);
       
   320 +
       
   321 +	/*
       
   322 +	 * 2**32 % x == (2**32 - x) % x
       
   323 +	 * (Trick comes from OpenBSD, arc4random_uniform.c)
       
   324 +	 */
       
   325 +	min = -upper_bound % upper_bound;
       
   326 +	for (;;) {
       
   327 +		if (getrandom(&rand, sizeof (rand), GRND_NONBLOCK) !=
       
   328 +		    sizeof (rand))
       
   329 +			return (UINT32_MAX);
       
   330 +		if (rand >= min)
       
   331 +			break;
       
   332 +	}
       
   333 +
       
   334 +	return (rand % upper_bound);
       
   335 +}
       
   336 +#endif	/* _SOLARIS_ */
       
   337 +
       
   338  void
       
   339  client_error(struct bufferevent *bufev, short what, void *arg)
       
   340  {
       
   341 @@ -220,6 +304,12 @@
       
   342  			return (0);
       
   343  		}
       
   344  		s->proxy_port = pick_proxy_port();
       
   345 +#ifdef _SOLARIS_
       
   346 +		if (s->proxy_port == UINT16_MAX) {
       
   347 +			logmsg(LOG_CRIT, "pick_proxy_port() failed");
       
   348 +			return (0);
       
   349 +		}
       
   350 +#endif /* _SOLARIS_ */
       
   351  		proxy_reply(s->cmd, sstosa(&s->proxy_ss), s->proxy_port);
       
   352  		logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf);
       
   353  	}
       
   354 @@ -378,13 +468,30 @@
       
   355  	struct sockaddr *proxy_to_server_sa;
       
   356  	struct session *s;
       
   357  	socklen_t len;
       
   358 +#ifdef _SOLARIS_
       
   359 +	socklen_t client_sa_len, server_sa_len;
       
   360 +	int one = 1; /* parameter for setsockopt */
       
   361 +#endif	/* _SOLARIS_ */
       
   362  	int client_fd, fc, on;
       
   363 -
       
   364 +	/*
       
   365 +	 * We experienced big problems when event_add() was called
       
   366 +	 * before accepting the incoming connection - for some reason,
       
   367 +	 * a new event was fired immediately and ftp-proxy was hanged
       
   368 +	 * trying to accept another client that was not there yet.
       
   369 +	 * Moving event_add() call a few lines below resolved this
       
   370 +	 * problem.
       
   371 +	 */
       
   372 +#ifndef _SOLARIS_
       
   373  	event_add(&listen_ev, NULL);
       
   374 +#endif	/* !_SOLARIS_ */
       
   375  
       
   376 -	if ((event & EV_TIMEOUT))
       
   377 +	if ((event & EV_TIMEOUT)) {
       
   378 +#ifdef _SOLARIS_
       
   379 +		event_add(&listen_ev, NULL);
       
   380 +#endif	/* _SOLARIS_ */
       
   381  		/* accept() is no longer paused. */
       
   382  		return;
       
   383 +	}
       
   384  
       
   385  	/*
       
   386  	 * We _must_ accept the connection, otherwise libevent will keep
       
   387 @@ -393,6 +500,9 @@
       
   388  	client_sa = sstosa(&tmp_ss);
       
   389  	len = sizeof(struct sockaddr_storage);
       
   390  	if ((client_fd = accept(listen_fd, client_sa, &len)) < 0) {
       
   391 +#ifdef _SOLARIS_
       
   392 +		event_add(&listen_ev, NULL);
       
   393 +#endif	/* _SOLARIS_ */
       
   394  		logmsg(LOG_CRIT, "accept() failed: %s", strerror(errno));
       
   395  
       
   396  		/*
       
   397 @@ -410,6 +520,16 @@
       
   398  		return;
       
   399  	}
       
   400  
       
   401 +#ifdef _SOLARIS_
       
   402 +	event_add(&listen_ev, NULL);
       
   403 +
       
   404 +	/*
       
   405 +	 * Struct sockaddr does not contain sa_len field on Solaris,
       
   406 +	 * we use client_sa_len instead.
       
   407 +	 */
       
   408 +	client_sa_len = len;
       
   409 +#endif	/* _SOLARIS_ */
       
   410 +
       
   411  	/* Refuse connection if the maximum is reached. */
       
   412  	if (session_count >= max_sessions) {
       
   413  		logmsg(LOG_ERR, "client limit (%d) reached, refusing "
       
   414 @@ -426,8 +546,11 @@
       
   415  		return;
       
   416  	}
       
   417  	s->client_fd = client_fd;
       
   418 +#ifdef _SOLARIS_
       
   419 +	memcpy(sstosa(&s->client_ss), client_sa, client_sa_len);
       
   420 +#else /* !_SOLARIS_ */
       
   421  	memcpy(sstosa(&s->client_ss), client_sa, client_sa->sa_len);
       
   422 -
       
   423 +#endif	/* _SOLARIS_ */
       
   424  	/* Cast it once, and be done with it. */
       
   425  	client_sa = sstosa(&s->client_ss);
       
   426  	server_sa = sstosa(&s->server_ss);
       
   427 @@ -447,6 +570,17 @@
       
   428  		    strerror(errno));
       
   429  		goto fail;
       
   430  	}
       
   431 +#ifdef _SOLARIS_
       
   432 +	/*
       
   433 +	 * Struct sockaddr does not contain sa_len field on Solaris,
       
   434 +	 * we use server_sa_len instead.
       
   435 +	 */
       
   436 +	server_sa_len = len;
       
   437 +#endif	/* _SOLARIS_ */
       
   438 +/* SO_RTABLE not defined on Solaris */
       
   439 +#ifdef _SOLARIS_
       
   440 +	s->client_rd = 0;
       
   441 +#else /* !_SOLARIS_ */
       
   442  	len = sizeof(s->client_rd);
       
   443  	if (getsockopt(s->client_fd, SOL_SOCKET, SO_RTABLE, &s->client_rd,
       
   444  	    &len) && errno != ENOPROTOOPT) {
       
   445 @@ -454,10 +588,18 @@
       
   446  		    strerror(errno));
       
   447  		goto fail;
       
   448  	}
       
   449 +#endif	/* _SOLARIS_ */
       
   450  	if (fixed_server) {
       
   451 +#ifdef _SOLARIS_
       
   452 +		memcpy(sstosa(&s->orig_server_ss), server_sa,
       
   453 +		    server_sa_len);
       
   454 +		memcpy(server_sa, fixed_server_sa, fixed_server_ss_len);
       
   455 +		server_sa_len = fixed_server_ss_len; /* update the length */
       
   456 +#else /* !_SOLARIS_ */
       
   457  		memcpy(sstosa(&s->orig_server_ss), server_sa,
       
   458  		    server_sa->sa_len);
       
   459  		memcpy(server_sa, fixed_server_sa, fixed_server_sa->sa_len);
       
   460 +#endif	/* _SOLARIS_ */
       
   461  	}
       
   462  
       
   463  	/* XXX: check we are not connecting to ourself. */
       
   464 @@ -471,8 +613,14 @@
       
   465  		    strerror(errno));
       
   466  		goto fail;
       
   467  	}
       
   468 +#ifdef	_SOLARIS_
       
   469  	if (fixed_proxy && bind(s->server_fd, sstosa(&fixed_proxy_ss),
       
   470 -	    fixed_proxy_ss.ss_len) != 0) {
       
   471 +	    fixed_proxy_ss_len) != 0)
       
   472 +#else /* !_SOLARIS_ */
       
   473 +	if (fixed_proxy && bind(s->server_fd, sstosa(&fixed_proxy_ss),
       
   474 +	    fixed_proxy_ss.ss_len) != 0)
       
   475 +#endif	/* _SOLARIS_ */
       
   476 +	{
       
   477  		logmsg(LOG_CRIT, "#%d cannot bind fixed proxy address: %s",
       
   478  		    s->id, strerror(errno));
       
   479  		goto fail;
       
   480 @@ -485,8 +633,14 @@
       
   481  		    s->id, strerror(errno));
       
   482  		goto fail;
       
   483  	}
       
   484 +#ifdef _SOLARIS_
       
   485 +	if (connect(s->server_fd, server_sa, server_sa_len) < 0 &&
       
   486 +	    errno != EINPROGRESS)
       
   487 +#else /* !_SOLARIS_ */
       
   488  	if (connect(s->server_fd, server_sa, server_sa->sa_len) < 0 &&
       
   489 -	    errno != EINPROGRESS) {
       
   490 +	    errno != EINPROGRESS)
       
   491 +#endif	/* _SOLARIS_ */
       
   492 +	{
       
   493  		logmsg(LOG_CRIT, "#%d proxy cannot connect to server %s: %s",
       
   494  		    s->id, sock_ntop(server_sa), strerror(errno));
       
   495  		goto fail;
       
   496 @@ -592,6 +746,9 @@
       
   497  		/* syslog does its own vissing. */
       
   498  		vsyslog(pri, message, ap);
       
   499  	else {
       
   500 +#ifdef _SOLARIS_
       
   501 +		vsyslog(pri, message, ap);
       
   502 +#else /* !_SOLARIS_ */
       
   503  		char buf[MAX_LOGLINE];
       
   504  		char visbuf[2 * MAX_LOGLINE];
       
   505  
       
   506 @@ -599,6 +756,7 @@
       
   507  		vsnprintf(buf, sizeof buf, message, ap);
       
   508  		strnvis(visbuf, buf, sizeof visbuf, VIS_CSTYLE | VIS_NL);
       
   509  		fprintf(stderr, "%s\n", visbuf);
       
   510 +#endif	/* _SOLARIS_ */
       
   511  	}
       
   512  
       
   513  	va_end(ap);
       
   514 @@ -636,9 +794,11 @@
       
   515  
       
   516  	while ((ch = getopt(argc, argv, "6Aa:b:D:dm:P:p:q:R:rT:t:v")) != -1) {
       
   517  		switch (ch) {
       
   518 +#ifndef	_SOLARIS_
       
   519  		case '6':
       
   520  			ipv6_mode = 1;
       
   521  			break;
       
   522 +#endif	/* !_SOLARIS_ */
       
   523  		case 'A':
       
   524  			anonymous_only = 1;
       
   525  			break;
       
   526 @@ -668,11 +828,13 @@
       
   527  		case 'p':
       
   528  			listen_port = optarg;
       
   529  			break;
       
   530 +#ifndef	_SOLARIS_
       
   531  		case 'q':
       
   532  			if (strlen(optarg) >= PF_QNAME_SIZE)
       
   533  				errx(1, "queuename too long");
       
   534  			qname = optarg;
       
   535  			break;
       
   536 +#endif	/* !_SOLARIS_ */
       
   537  		case 'R':
       
   538  			fixed_server = optarg;
       
   539  			break;
       
   540 @@ -718,9 +880,16 @@
       
   541  		hints.ai_socktype = SOCK_STREAM;
       
   542  		error = getaddrinfo(fixed_proxy, NULL, &hints, &res);
       
   543  		if (error)
       
   544 -			errx(1, "getaddrinfo fixed proxy address failed: %s",
       
   545 +			errx(1, "getaddrinfo fixed proxy address (%s) failed: %s", fixed_proxy,
       
   546  			    gai_strerror(error));
       
   547  		memcpy(&fixed_proxy_ss, res->ai_addr, res->ai_addrlen);
       
   548 +#ifdef _SOLARIS_
       
   549 +		/*
       
   550 +		 * struct sockaddr_storage does not have the member
       
   551 +		 * ss_len on Solaris, thus we use a global variable.
       
   552 +		 */
       
   553 +		fixed_proxy_ss_len = res->ai_addrlen;
       
   554 +#endif	/* _SOLARIS_ */
       
   555  		logmsg(LOG_INFO, "using %s to connect to servers",
       
   556  		    sock_ntop(sstosa(&fixed_proxy_ss)));
       
   557  		freeaddrinfo(res);
       
   558 @@ -736,6 +905,13 @@
       
   559  			errx(1, "getaddrinfo fixed server address failed: %s",
       
   560  			    gai_strerror(error));
       
   561  		memcpy(&fixed_server_ss, res->ai_addr, res->ai_addrlen);
       
   562 +#ifdef _SOLARIS_
       
   563 +		/*
       
   564 +		 * struct sockaddr_storage does not have the member
       
   565 +		 * ss_len on Solaris, thus we use a global variable.
       
   566 +		 */
       
   567 +		fixed_server_ss_len = res->ai_addrlen;
       
   568 +#endif	/* _SOLARIS_ */
       
   569  		logmsg(LOG_INFO, "using fixed server %s",
       
   570  		    sock_ntop(sstosa(&fixed_server_ss)));
       
   571  		freeaddrinfo(res);
       
   572 @@ -752,6 +928,11 @@
       
   573  		    gai_strerror(error));
       
   574  	if ((listenfd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
       
   575  		errx(1, "socket failed");
       
   576 +#ifdef _SOLARIS_
       
   577 +	if (setsockopt(listenfd, SOL_FILTER, FIL_ATTACH, DIVERT_MODULE_NAME,
       
   578 +	    (strlen(DIVERT_MODULE_NAME)+1)) != 0)
       
   579 +		err(1, "setsockopt failed - unable to attach filter");
       
   580 +#endif /* _SOLARIS_ */
       
   581  	on = 1;
       
   582  	if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
       
   583  	    sizeof on) != 0)
       
   584 @@ -782,7 +963,11 @@
       
   585  	event_init();
       
   586  
       
   587  	/* Setup signal handler. */
       
   588 +#ifdef	_SOLARIS_
       
   589 +	sigset(SIGPIPE, SIG_IGN);
       
   590 +#else /* !_SOLARIS_ */
       
   591  	signal(SIGPIPE, SIG_IGN);
       
   592 +#endif	/* _SOLARIS_ */
       
   593  	signal_set(&ev_sighup, SIGHUP, handle_signal, NULL);
       
   594  	signal_set(&ev_sigint, SIGINT, handle_signal, NULL);
       
   595  	signal_set(&ev_sigterm, SIGTERM, handle_signal, NULL);
       
   596 @@ -857,12 +1042,25 @@
       
   597  	return (0);
       
   598  }
       
   599  
       
   600 +/*
       
   601 + * On Solaris, fake_arc4random_uniform() can fail. We return UINT16_MAX
       
   602 + * on error.
       
   603 + */
       
   604  u_int16_t
       
   605  pick_proxy_port(void)
       
   606  {
       
   607 +#ifdef _SOLARIS_
       
   608 +	u_int32_t shift;
       
   609 +
       
   610 +	shift = fake_arc4random_uniform(IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO);
       
   611 +	if (shift == UINT32_MAX)
       
   612 +		return UINT16_MAX;
       
   613 +	return (IPPORT_HIFIRSTAUTO + shift);
       
   614 +#else /* !_SOLARIS_ */
       
   615  	/* Random should be good enough for avoiding port collisions. */
       
   616  	return (IPPORT_HIFIRSTAUTO +
       
   617  	    arc4random_uniform(IPPORT_HILASTAUTO - IPPORT_HIFIRSTAUTO));
       
   618 +#endif /* _SOLARIS_ */
       
   619  }
       
   620  
       
   621  void
       
   622 @@ -985,6 +1183,12 @@
       
   623  			return (0);
       
   624  		}
       
   625  		s->proxy_port = pick_proxy_port();
       
   626 +#ifdef _SOLARIS_
       
   627 +		if (s->proxy_port == UINT16_MAX) {
       
   628 +			logmsg(LOG_CRIT, "pick_proxy_port() failed");
       
   629 +			return (0);
       
   630 +		}
       
   631 +#endif /* _SOLARIS_ */
       
   632  		logmsg(LOG_INFO, "#%d passive: client to server port %d"
       
   633  		    " via port %d", s->id, s->port, s->proxy_port);
       
   634  
       
   635 @@ -1126,6 +1330,6 @@
       
   636  	fprintf(stderr, "usage: %s [-6Adrv] [-a address] [-b address]"
       
   637  	    " [-D level] [-m maxsessions]\n                 [-P port]"
       
   638  	    " [-p port] [-q queue] [-R address] [-T tag]\n"
       
   639 -            "                 [-t timeout]\n", __progname);
       
   640 +	    "                 [-t timeout]\n", __progname);
       
   641  	exit(1);
       
   642  }