/*
 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
 *               2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016, 2017
 *      Inferno Nettverk A/S, Norway.  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. The above copyright notice, this list of conditions and the following
 *    disclaimer must appear in all copies of the software, derivative works
 *    or modified versions, and any portions thereof, aswell as in all
 *    supporting documentation.
 * 2. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by
 *      Inferno Nettverk A/S, Norway.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * 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.
 *
 * Inferno Nettverk A/S requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  sdc@inet.no
 *  Inferno Nettverk A/S
 *  Oslo Research Park
 *  Gaustadalléen 21
 *  NO-0349 Oslo
 *  Norway
 *
 * any improvements or extensions that they make and grant Inferno Nettverk A/S
 * the rights to redistribute these changes.
 *
 */

/* $Id: common.h,v 1.931.4.7.2.8 2017/02/03 14:13:14 karls Exp $ */

#ifndef _COMMON_H_
#define _COMMON_H_

/* ifdef, not if, defined on command line */
#ifdef HAVE_CONFIG_H
#include "autoconf.h"
#endif /* HAVE_CONFIG_H */

#ifndef NO_OSDEP
#include "osdep.h"
#endif /* !NO_OSDEP */

#include "yacconfig.h"

#include "config.h"

/* global variables needed by everyone. */
extern struct config sockscf;
extern char *__progname;

   /*
    * defines
    */

/*
 * If we are compiling for unit-tests, there are functions
 * that normally have static/file-local scope, but which we
 * want to test in the unit-tests.  The below #define is used as
 * an easy way to make those functions be compiled with global
 * scope for unit-tests.
 */
#if STANDALONE_UNIT_TEST
#define UNIT_TEST_STATIC_SCOPE
#else
#define UNIT_TEST_STATIC_SCOPE static
#endif

#if DIAGNOSTIC
/*
 * Takes too much time, leading to one or more shmem-files usually having
 * been deleted already by mother before child-processes get around to
 * checking them.  Instead enable this only if we (again) suspect there
 * are bugs related to corruption of the shmem-header.
 */
#define DO_SHMEMCHECK (0)
#else
#define DO_SHMEMCHECK (0)
#endif


/*
 * We base ourselves on RFC 5424. (LOG_ALERT (0) - LOG_DEBUG (7))
 */
#define MAXLOGLEVELS        (8)


#define PIPEBUFFER_IS_SEND_BASED       (0)
#define PIPEBUFFER_IS_RECV_BASED       (1)
#define PIPEBUFFER_IS_UNKNOWN_BASED    (0)

#if HAVE_SOLARIS_BUGS
#define HAVE_UNIQUE_SOCKET_INODES   (0)
#else /* !HAVE_SOLARIS_BUGS */
#define HAVE_UNIQUE_SOCKET_INODES   (1)
#endif /* HAVE_SOLARIS_BUGS */

#define SOCKS_IGNORE_SIGNALSAFETY   (0)

#if PRERELEASE

/*
 * Solaris 2.5.1 and it's stream stuff is broken and puts the processes
 * into never-never land forever on half the sendmsg() calls if they
 * involve ancillary data.  (it seems to deadlock the processes.)
 * XXX need to retest what the current status of this is.
 */
/* always enable if PRERELEASE */
#undef HAVE_SENDMSG_DEADLOCK
#define HAVE_SENDMSG_DEADLOCK 1

#endif /* PRERELEASE */

#define TOIN(addr) ((struct sockaddr_in *)(addr))
#define TOCIN(addr) ((const struct sockaddr_in *)(addr))

#define TOIN6(addr) ((struct sockaddr_in6 *)(addr))
#define TOCIN6(addr) ((const struct sockaddr_in6 *)(addr))

#define TOSA(addr) ((struct sockaddr *)addr)
#define TOCSA(addr) ((const struct sockaddr *)addr)
#define TOSS(addr) ((struct sockaddr_storage *)addr)
#define TOCSS(addr) ((const struct sockaddr_storage *)addr)

#define IP_MAXPORT (65535)   /* max value for ip port number. */


/*
 * redefine system limits to match that of socks protocol.
 * No need for these to be bigger than protocol allows, but they
 * _must_ be at least as big as protocol allows.
 */

#ifdef   MAXHOSTNAMELEN
#undef   MAXHOSTNAMELEN
#endif /* MAXHOSTNAMELEN */
#define  MAXHOSTNAMELEN    (255 + 1)      /* socks5: 255, +1 for len. */

#ifndef  MAXSERVICELEN
#define  MAXSERVICELEN    (255 + 1)       /* aka /etc/services. */
#endif /* MAXSERVICELEN */


#ifdef   MAXURLLEN
#undef   MAXURLLEN
#endif /* MAXURLLEN */
#define  MAXURLLEN         (255 + 1)      /* whatever. */

#ifdef   MAXNAMELEN
#undef   MAXNAMELEN
#endif /* MAXNAMELEN */
#define  MAXNAMELEN        (255 + 1)      /* socks5: 255, +1 for len. */

#ifdef   MAXPWLEN
#undef   MAXPWLEN
#endif /* MAXPWLEN */
#define  MAXPWLEN          (255 + 1)      /* socks5: 255, +1 for len. */

#define MAXTCPINFOLEN      (2048)

#if HAVE_GSSAPI
#ifdef MAXGSSAPITOKENLEN
#undef MAXGSSAPITOKENLEN
#endif /* MAXGSSAPITOKENLEN */
#define MAXGSSAPITOKENLEN (1024 * 64 - 1) /* socks5: up to 2^16 - 1 */

/*
 * GSSAPI headerlen (NOTE: SOCKS GSSAPI headerlen.  After stripping of
 * the socks gssapi header, there is another non-socks gssapi header
 * also on the token).
 */
#define GSSAPI_HLEN       (4)

/*
 * XXX should be max-size of exported state, but we don't know what it is.
 * Is there any way to find out?
 */
#define MAX_GSS_STATE     (2000)

#endif /* HAVE_GSSAPI */

/* max number of socket options to set on the external side, per rule. */
#define MAX_EXTERNAL_SOCKETOPTIONS (5)

#define   MAXIFNAMELEN      (255)

#define   MAXSOCKADDRSTRING  \
               (sizeof("0000:0000:0000:0000:0000:0000:0000:0000.65535"))

/*                                             "." + "65535" + NUL */
#define   MAXSOCKSHOSTSTRING (MAXHOSTNAMELEN + 1  +    5)
#define   MINSOCKSHOSTLEN    (   1 /* ATYPE              */      \
                             +   2 /* DST.ADDR (LEN + 1) */      \
                             +   2 /* DST.PORT           */)

#define   MAXSOCKSHOSTLEN    (   1               /* ATYPE              */      \
                             +   1               /* DST.ADDR LEN       */      \
                             +   MAXHOSTNAMELEN  /* DST.ADDR           */      \
                             +   2               /* DST.PORT           */)

#define   MINSOCKSUDPHLEN    (   2 /* RSV                */      \
                             +   1 /* FRAG               */      \
                             +   MINSOCKSHOSTLEN)

#define   MAXSOCKSUDPHLEN    (   2 /* RSV                */      \
                             +   1 /* FRAG               */      \
                             +   MAXSOCKSHOSTLEN)

#define   MAXRULEADDRSTRING  (MAXSOCKSHOSTSTRING * 2 + 32 /* atype, etc. */)
#define   MAXGWSTRING        (MAXSOCKSHOSTSTRING)


#define MAXSUBDOMAINS        (10) /* a.b.c.d.e.f ... */


#define MAXAUTHINFOLEN      (((sizeof("(") - 1) + MAXMETHODSTRING) \
                           + (sizeof(")") - 1) + (sizeof("@") - 1) + MAXNAMELEN)


#define MAXFACILITYNAMELEN    (8 + 1) /* max length of syslog facility name. */

#ifndef NUL
#define NUL '\0'
#endif /* !NUL */

#define CONFIGTYPE_SERVER      1
#define CONFIGTYPE_CLIENT      2

#define PROTOCOL_TCPs         "tcp"
#define PROTOCOL_UDPs         "udp"
#define PROTOCOL_UNKNOWNs      "unknown"

#define SOCKS_TCP             (1)
#define SOCKS_UDP             (2)

#define RESOLVEPROTOCOL_UDP   (SOCKS_UDP)
#define RESOLVEPROTOCOL_TCP   (SOCKS_TCP)
#define RESOLVEPROTOCOL_FAKE  (3)

#define LOGTYPE_SYSLOG        0x1
#define LOGTYPE_FILE          0x2

/*
 * Some things we may want to log at different levels in the server and
 * the client.  Use #defines here that map to the appropriate level.
 */
#if SOCKS_CLIENT
#define LOG_NEGOTIATE         (LOG_INFO)
#else /* SOCKS_SERVER */
#define LOG_NEGOTIATE         (LOG_DEBUG)
#endif


#define NOMEM                 "<memory exhausted>"

/* environment variables used. */
#define ENV_HTTP_PROXY                     "HTTP_CONNECT_PROXY"
#define ENV_SOCKS4_SERVER                  "SOCKS4_SERVER"
#define ENV_SOCKS5_PASSWD                  "SOCKS5_PASSWD"
#define ENV_SOCKS5_SERVER                  "SOCKS5_SERVER"
#define ENV_SOCKS5_USER                    "SOCKS5_USER"
#define ENV_SOCKS_BINDLOCALONLY            "SOCKS_BINDLOCALONLY"
#define ENV_SOCKS_CONF                     "SOCKS_CONF"
#define ENV_SOCKS_DEBUG                    "SOCKS_DEBUG"
#define ENV_SOCKS_DIRECTROUTE_FALLBACK     "SOCKS_DIRECTROUTE_FALLBACK"
#define ENV_SOCKS_DISABLE_THREADLOCK       "SOCKS_DISABLE_THREADLOCK"
#define ENV_SOCKS_ERRLOGOUTPUT             "SOCKS_ERRLOGOUTPUT"
#define ENV_SOCKS_FORCE_BLOCKING_CONNECT   "SOCKS_FORCE_BLOCKING_CONNECT"
#define ENV_SOCKS_LOGOUTPUT                "SOCKS_LOGOUTPUT"
#define ENV_SOCKS_PASSWD                   "SOCKS_PASSWD"
#define ENV_SOCKS_PASSWORD                 "SOCKS_PASSWORD"
#define ENV_SOCKS_ROUTE_                   "SOCKS_ROUTE_"   /* _<number> */
#define ENV_SOCKS_SERVER                   "SOCKS_SERVER"
#define ENV_SOCKS_USER                     "SOCKS_USER"
#define ENV_SOCKS_USERNAME                 "SOCKS_USERNAME"
#define ENV_TMPDIR                         "TMPDIR"
#define ENV_UPNP_IGD                       "UPNP_IGD"
#define ENV_SOCKS_AUTOADD_LANROUTES        "SOCKS_AUTOADD_LANROUTES"
#define ENV_SOCKS_REDIRECT_FROM            "SOCKS_REDIRECT_FROM"

   /*
    * macros
    */

/*
 * CompileTime assert.  Based on an article in DrDobbs by Ralf Holly.
 * (http://www.drdobbs.com/compile-time-assertions/184401873)
 */
#define CTASSERT(exp)                     \
do {                                      \
   enum { assert_static__ = 1/(exp) };    \
} while (/* CONSTCOND */ 0)

/*
 * Error macros.
 */

#if HAVE_LIVEDEBUG /* try to generate a coredump and continue if server. */

#if SOCKS_CLIENT
#define SET_INTERNAL_ERROR() do {                                              \
   sockscf.state.internalerrordetected = 1;                                    \
} while (/* CONSTCOND */ 0)

#else /* !SOCKS_CIENT */
#define SET_INTERNAL_ERROR() do { } while (/* CONSTCOND */ 0)
#endif /* !SOCKS_CLIENT */

#define HANDLE_RINGBUFFER()                                                    \
do {                                                                           \
   SET_INTERNAL_ERROR();                                                       \
                                                                               \
   if (!sockscf.option.debug)                                                  \
      socks_flushrb();                                                         \
} while (/* CONSTCOND */ 0)

#else  /* !HAVE_LIVEDEBUG */
#define HANDLE_RINGBUFFER() do { } while (/* CONSTCOND */ 0)

#endif /* !HAVE_LIVEDEBUG */

#define SASSERT_STARTSTRING "an internal error was detected at "
#define SASSERT_ENDSTRING   \
"Please report this to Inferno Nettverk A/S at \"" LCPRODUCT "-bugs@inet.no\"."\
"  Please check for a coredump too."

#define SIGNALSLOG_WITH_ERRNO(value, expstr, err)                              \
do {                                                                           \
   char _b[10][32];                                                            \
   const char *_msgv[]                                                         \
   = { SASSERT_STARTSTRING,                                                    \
       __FILE__,                                                               \
       ":",                                                                    \
       ltoa(__LINE__, _b[0], sizeof(_b[0])),                                   \
       ", value ",                                                             \
       ltoa((value), _b[1], sizeof(_b[1])),                                    \
       ", expression \"",                                                      \
       (expstr),                                                               \
       "\", errno ",                                                           \
       ltoa(err, _b[2], sizeof(_b[2])),                                        \
       " (",                                                                   \
       strerror(errno),                                                        \
       ").  Version: ",                                                        \
       rcsid,                                                                  \
       ".  ",                                                                  \
       SASSERT_ENDSTRING,                                                      \
       NULL                                                                    \
     };                                                                        \
                                                                               \
   signalslog(LOG_WARNING, _msgv);                                             \
} while (/* CONSTCOND */ 0)                                                    \

#define SIGNALSLOG_WITHOUT_ERRNO(value, expstr)                                \
do {                                                                           \
   char _b[10][32];                                                           \
   const char *_msgv[]                                                         \
   = { SASSERT_STARTSTRING,                                                    \
       __FILE__,                                                               \
       ":",                                                                    \
       ltoa(__LINE__, _b[0], sizeof(_b[0])),                                   \
       ", value ",                                                             \
       ltoa((value), _b[1], sizeof(_b[1])),                                    \
       ", expression \"",                                                      \
       (expstr),                                                               \
       "\"",                                                                   \
       ".  Version: ",                                                         \
       rcsid,                                                                  \
       ".  ",                                                                  \
       SASSERT_ENDSTRING,                                                      \
       NULL                                                                    \
     };                                                                        \
                                                                               \
   signalslog(LOG_WARNING, _msgv);                                             \
} while (/* CONSTCOND */ 0)

#define SIGNALSLOG_WITH_ERRNO_FAD(_value, expstr, err)                         \
do {                                                                           \
   char _b[10][32];                                                           \
   const char *_msgv[]                                                         \
   = { SASSERT_STARTSTRING,                                                    \
       __FILE__,                                                               \
       ":",                                                                    \
       ltoa(__LINE__, _b[0], sizeof(_b[0])),                                   \
       ", by pid ",                                                            \
       ltoa(getppid(), _b[1], sizeof(_b[1])),                                  \
       ".  Value ",                                                            \
       ltoa((_value), _b[2], sizeof(_b[2])),                                   \
       ", expression \"",                                                      \
       (expstr),                                                               \
       "\", errno ",                                                           \
       ltoa(err, _b[3], sizeof(_b[3])),                                        \
       " (",                                                                   \
       strerror(errno),                                                        \
       ").  Version: ",                                                        \
       rcsid,                                                                  \
       ".  ",                                                                  \
       SASSERT_ENDSTRING,                                                      \
       NULL                                                                    \
     };                                                                        \
                                                                               \
   signalslog(LOG_WARNING, _msgv);                                             \
} while (/* CONSTCOND */ 0)                                                    \

#define SIGNALSLOG_WITHOUT_ERRNO_FAD(_value, expstr)                           \
do {                                                                           \
   char _b[10][32];                                                           \
   const char *_msgv[]                                                         \
   = { SASSERT_STARTSTRING,                                                    \
       __FILE__,                                                               \
       ":",                                                                    \
       ltoa(__LINE__, _b[0], sizeof(_b[0])),                                   \
       ", by pid ",                                                            \
       ltoa(getppid(), _b[1], sizeof(_b[1])),                                  \
       ".  Value ",                                                            \
       ltoa((_value), _b[2], sizeof(_b[2])),                                   \
       ", expression \"",                                                      \
       (expstr),                                                               \
       "\"",                                                                   \
       ".  Version: ",                                                         \
       rcsid,                                                                  \
       ".  ",                                                                  \
       SASSERT_ENDSTRING,                                                      \
       NULL                                                                    \
     };                                                                        \
                                                                               \
   signalslog(LOG_WARNING, _msgv);                                             \
} while (/* CONSTCOND */ 0)

#define SERR_BODY(_value, expstr, _err)                                        \
do {                                                                           \
   const int err = (_err);                                                     \
                                                                               \
   SIGNALSLOG_WITH_ERRNO(_value, expstr, err);                                 \
   HANDLE_RINGBUFFER();                                                        \
   abort();                                                                    \
} while (/* CONSTCOND */ 0)

                                                                               \
#define SERRX_BODY(_value, expstr)                                             \
do {                                                                           \
   SIGNALSLOG_WITHOUT_ERRNO(_value, expstr);                                   \
   HANDLE_RINGBUFFER();                                                        \
   abort();                                                                    \
} while (/* CONSTCOND */ 0)


#define SWARN_BODY(_value, expstr, _err)                                       \
do {                                                                           \
   pid_t forked;                                                               \
   const int err = (_err);                                                     \
                                                                               \
   switch ((forked = fork())) {                                                \
      case -1:                                                                 \
         SIGNALSLOG_WITH_ERRNO(_value, expstr, err);                           \
         break;                                                                \
                                                                               \
      case 0:                                                                  \
         newprocinit();                                                        \
         SIGNALSLOG_WITH_ERRNO_FAD(_value, expstr, err);                       \
         HANDLE_RINGBUFFER();                                                  \
         abort();                                                              \
         break; /* NOTREACHED */                                               \
                                                                               \
      default:                                                                 \
         SIGNALSLOG_PARENT_CONTINUING(forked);                                 \
   }                                                                           \
} while (/* CONSTCOND */ 0)

#define SWARNX_BODY(_value, expstr)                                            \
do {                                                                           \
   pid_t forked;                                                               \
                                                                               \
   switch ((forked = fork())) {                                                \
      case -1:                                                                 \
         SIGNALSLOG_WITHOUT_ERRNO(_value, expstr);                             \
         break;                                                                \
                                                                               \
      case 0:                                                                  \
         newprocinit();                                                        \
         SIGNALSLOG_WITHOUT_ERRNO_FAD(_value, expstr);                         \
         HANDLE_RINGBUFFER();                                                  \
         abort();                                                              \
         break; /* NOTREACHED */                                               \
                                                                               \
      default:                                                                 \
         SIGNALSLOG_PARENT_CONTINUING(forked);                                 \
   }                                                                           \
} while (/* CONSTCOND */ 0)

#define SIGNALSLOG_PARENT_CONTINUING(childpid)                                 \
do {                                                                           \
   char _b[10][32];                                                            \
   const char *_msgv[]                                                         \
   = { "continuing after internal error.  Unless disabled on system we "       \
       "should have a coredump from pid ",                                     \
       ltoa(getpid(), _b[0], sizeof(_b[0])),                                   \
       " by way of pid ",                                                      \
       ltoa((childpid), _b[1], sizeof(_b[1])),                                 \
       " now",                                                                 \
       NULL                                                                    \
     };                                                                        \
                                                                               \
   signalslog(LOG_WARNING, _msgv);                                             \
} while (/* CONSTCOND */ 0)


#define SWARN(expression)                                                      \
do {                                                                           \
    const long _value = (const long)(expression);                              \
    const char *expstr = #expression;                                          \
                                                                               \
    SWARN_BODY(_value, expstr, errno);                                         \
} while (/* CONSTCOND */ 0)

#define SWARNX(expression)                                                     \
do {                                                                           \
    const long _value = (const long)(expression);                              \
    const char *expstr = #expression;                                          \
                                                                               \
    SWARNX_BODY(_value, expstr);                                               \
} while (/* CONSTCOND */ 0)

#define SERR(expression)                                                       \
do {                                                                           \
    const long _value = (const long)(expression);                              \
    const char *expstr = #expression;                                          \
                                                                               \
    SERR_BODY(_value, expstr, errno);                                          \
} while (/* CONSTCOND */ 0)

#define SERRX(expression)                                                      \
do {                                                                           \
    const long _value = (const long)(expression);                              \
    const char *expstr = #expression;                                          \
                                                                               \
    SERRX_BODY(_value, expstr);                                                \
} while (/* CONSTCOND */ 0)

#define SASSERT(expression)                                                    \
do {                                                                           \
   const long _value  = (const long)(expression);                              \
   const char *expstr = #expression;                                           \
                                                                               \
   if (_value == 0)                                                            \
      SERR_BODY(_value, expstr, errno);                                        \
} while (/* CONSTCOND */ 0)

#define SASSERTX(expression)                                                   \
do {                                                                           \
   const long _value  = (const long)(expression);                              \
   const char *expstr = #expression;                                           \
                                                                               \
   if (_value == 0)                                                            \
      SERRX_BODY(_value, expstr);                                              \
} while (/* CONSTCOND */ 0)

#if 0
/* so we can attach to the process while it's alive ... */
#define abort() do { sleep(60); } while (1)
#endif


/*
 * Make sure length of "_src" is not larger than the size of "_dst".
 */
#define STRCPY_ASSERTLEN(__dst, __src)                                         \
do {                                                                           \
   const void *_src   = (__src);                                               \
   const size_t _len = strlen((const char *)_src);                             \
   void *_dst        = (__dst);                                                \
                                                                               \
   SASSERTX(_len <= (sizeof((__dst)) - 1));                                    \
   memcpy((_dst), (_src), _len + 1);                                           \
} while (/* CONSTCOND */ 0)


/*
 * Round up or down a struct timeval to whole seconds.
 */
#define timeval2seconds(tval)                                                  \
   ((tval)->tv_sec + ((tval)->tv_usec >= 500000 ? 1 : 0))


/*
 * Make sure length of "_src" is not lager than "maxlen", and copy it to _dst.
 */
#define STRCPY_CHECKLEN(__dst, __src, _maxlen, _function)                      \
do {                                                                           \
   const void *_src  = (__src);                                                \
   const size_t _len = strlen((const char *)_src);                             \
   void *_dst        = (__dst);                                                \
                                                                               \
   if (_len >= (_maxlen) - 1) {                                                \
      _function("the value given is %lu bytes long, but the maximum length, "  \
                "set at compiletime, is %lu",                                  \
                (unsigned long)(_len),                                         \
                (unsigned long)((_maxlen)));                                   \
       break;                                                                  \
   }                                                                           \
                                                                               \
   memcpy((_dst), (_src), _len + 1);                                           \
} while (/* CONSTCOND */ 0)


#define STRCPY_ASSERTSIZE(__dst, __src)                                        \
do {                                                                           \
   const void *_src  = (__src);                                                \
   const size_t _len = strlen((const char *)_src);                             \
   void *_dst        = (__dst);                                                \
                                                                               \
   CTASSERT(sizeof((__dst)) >= sizeof((__src)));                               \
   SASSERTX(_len + 1 <= sizeof((__dst)));                                      \
   SASSERTX(_len + 1 <= sizeof((__src)));                                      \
                                                                               \
   memcpy((_dst), (_src), _len + 1);                                           \
} while (0 /* CONSTCOND */)


#define STRCPY_CHECKUTFLEN(__dst, __src, _maxlen, _function)                   \
do {                                                                           \
   const void *_src  = (__src);                                                \
   const size_t _len = strlen((const char *)__src);                            \
   void *_dst        = (__dst);                                                \
   char *utfsrc;                                                               \
                                                                               \
   if (_len / 2 >= ((_maxlen) - 1)) {                                          \
      _function("the value given is %lu bytes long, but the maximum length, "  \
               "set at compiletime, is %lu",                                   \
               (unsigned long)(_len / 2),                                      \
               (unsigned long)((_maxlen) - 1));                                \
       break;                                                                  \
   }                                                                           \
                                                                               \
   if ((utfsrc = hextoutf8((const char *)_src, 2)) == NULL)                    \
      _function("failed to convert string \"%s\" to UTF-8",                    \
                (const char *)_src);                                           \
                                                                               \
   strncpy((char *)_dst, utfsrc, (_maxlen) - 1);                               \
   ((char *)(_dst))[(_maxlen) - 1] = NUL;                                      \
} while (/* CONSTCOND */ 0)


#define TVMIN(a, b) \
   (timercmp((a), (b), <) ? (a) : (b))

#define TVMAX(a, b) \
   (timercmp((a), (b), >) ? (a) : (b))


/*
 * Can not call these function directly since we need to make sure unused
 * bytes in the destination are zero (requirement of the socket API),
 * but the size of the destination can vary. :-/
 */

#define sockshost2sockaddr2(host, addr, gaierr, emsg, emsglen)                 \
   int_sockshost2sockaddr2((host),                                             \
                           (addr),                                             \
                           sizeof((*addr)),                                    \
                           (gaierr),                                           \
                           (emsg),                                             \
                           (emsglen))                                          \

#define sockshost2sockaddr(host, addr)                                         \
   int_sockshost2sockaddr((host), addr, sizeof((*addr)))

#define fakesockshost2sockaddr(host, addr)                                     \
   int_fakesockshost2sockaddr((host), (addr), sizeof((*addr)))

#define urlstring2sockaddr(string, addr, gaierr, emsg, elen)                   \
   int_urlstring2sockaddr((string),                                            \
                          (addr),                                              \
                          sizeof((*addr)),                                     \
                          (gaierr),                                            \
                          (emsg),                                              \
                          (elen))

#define ruleaddr2sockaddr(ruleaddr, addr, protocol)                            \
   int_ruleaddr2sockaddr((ruleaddr), (addr), sizeof((*addr)), (protocol))

#define ruleaddr2sockaddr2(ruleaddr, addr, protocol, gaierr, emsg, emsglen)    \
   int_ruleaddr2sockaddr2((ruleaddr),                                          \
                          (addr),                                              \
                          (sizeof((*addr))),                                   \
                          (protocol),                                          \
                          (gaierr),                                            \
                          (emsg),                                              \
                          (emsglen))

#define hostname2sockaddr(name, index, addr)                                   \
   int_hostname2sockaddr((name), (index), addr, sizeof((*addr)))

#define hostname2sockaddr2(name, index, addr, gaierr, emsg, emsglen)           \
   int_hostname2sockaddr2(name,                                                \
                          index,                                               \
                          addr,                                                \
                          sizeof((*addr)),                                     \
                          gaierr,                                              \
                          emsg,                                                \
                          emsglen)

#define ifname2sockaddr(ifname, index, addr, mask)                             \
   int_ifname2sockaddr((ifname),                                               \
                       (index),                                                \
                       (addr),                                                 \
                       sizeof((*addr)),                                        \
                       (mask),                                                 \
                       sizeof((*mask)))


#if HAVE_GSSAPI
#define GSSAPI_OVERHEAD(gssapistate) \
   ((MAXGSSAPITOKENLEN - GSSAPI_HLEN) - (gssapistate)->maxgssdata)

#define GSSERR_IS_OK(e)                                                        \
   (  (e) == GSS_S_CONTEXT_EXPIRED                                             \
   || (e) == GSS_S_CREDENTIALS_EXPIRED)
#endif /* HAVE_GSSAPI */

/*
 * Matched against sockscf.option.debug.  If the value there is
 * >= to DEBUG_NORMAL, do normal debug logging.  If >= DEBUG_VERBOSE,
 * do verbose, possibly expensive, debug logging also.
 */
#define DEBUG_NORMAL    (1)
#define DEBUG_VERBOSE   (2)
#define DEBUG_DEBUG     (9)   /* only for debuging problems. */

/*
 * If client, it might need to call malloc(3) to expand socksfdv
 * from the signal handler upon SIGIO, but if we are in a gssapi-function
 * that also is calling malloc(3) ... Still not safe of course, as we
 * have no idea if client is in a function that has called malloc(3).
 */
#if SOCKS_CLIENT

#define SOCKS_SIGBLOCK_IF_CLIENT(sig, oldset) \
do { socks_sigblock(sig, oldset); } while (/* CONSTCOND */ 0)

#define SOCKS_SIGUNBLOCK_IF_CLIENT(oldset) \
do { socks_sigunblock(oldset); } while (/* CONSTCOND */ 0)

#define SIGSET_ALLOCATE(name) sigset_t name

#else /* !SOCKS_CLIENT */
#define SIGSET_ALLOCATE(name)
#define SOCKS_SIGBLOCK_IF_CLIENT(sig, oldset)
#define SOCKS_SIGUNBLOCK_IF_CLIENT(oldset)
#endif /* !SOCKS_CLIENT */

/* due to external libraries/software trying to log to stdout/stderr. :-( */
#define FD_IS_RESERVED_EXTERNAL(fd)    \
   ((fd) == STDOUT_FILENO || (fd) == STDERR_FILENO)


/*
 * when using very large numbers (e.g., 9223372036854775807 on a 64 bit cpu),
 * difftime() returns strange results, even when the second arg is 0.
 * Don't know why, but converting the time_t value to double and
 * then back to time_t changes 9223372036854775807 to -9223372036854775808,
 * which seems to be what happens when we do the equivalent of
 * difftime(9223372036854775807, 0)
 *
 * The below seems to work better, so use it until we encounter a platform
 * where it does not work better.
 */
#define socks_difftime(t1, t2)  ((t1) - (t2))

/*
 * Wrappers for our own functions that modify things a little in a way
 * that should not have any negative effects.
 */
#define close(n)              closen((n))
#define socket(d, t, p)       socks_socket((d), (t), (p))
#define strerror(e)           socks_strerror((e))
#define getifaddrs(ifap)      socks_getifaddrs((ifap))
#define gai_strerror(errcode) socks_gai_strerror((errcode))

#undef snprintf
#define snprintf   snprintfn

/*
 * If "str", of size "strused", contains characters present in
 * "strip", strips them off from "str".
 */
#define STRIPTRAILING(str, strused, strip)      \
do {                                            \
   ssize_t i;                                   \
                                                \
   for (i = (ssize_t)(strused) - 1; i > 0; --i) \
      if (strchr((strip), str[i]) != NULL)      \
         (str)[i] = NUL;                        \
      else                                      \
         break;                                 \
} while (/* CONSTCOND */ 0)

#define SKIPLEADING(str, strip)                 \
do {                                            \
   while (*(str) != NUL)                        \
      if (strchr((strip), *(str)))              \
         ++(str);                               \
      else                                      \
         break;                                 \
} while (/* CONSTCOND */ 0)


/*
 * for dynamically-sized fd_sets.  Note that this means all our fd_set's
 * must be maxsize, or the macros we define will write over memory not
 * belonging to them.
 */

#ifndef howmany
#define howmany(x, y) (((x) + ((y) - 1)) / (y))
#endif /* !howmany */

#define SOCKD_FD_SIZE() \
((size_t)(howmany((sockscf.state.maxopenfiles + 1), NFDBITS) * sizeof(fd_mask)))

#ifdef FD_ZERO
#undef FD_ZERO
#endif /* FD_ZERO */

#define FD_ZERO(p)                      \
do {                                    \
   memset((p), 0, SOCKD_FD_SIZE());     \
} while (/* CONSTCOND */ 0)

#ifdef FD_CMP
#undef FD_CMP
#endif /* FD_CMP */

#define FD_CMP(a, b) (memcmp((a), (b), SOCKD_FD_SIZE()))

#ifdef FD_COPY
#undef FD_COPY
#endif /* FD_COPY */

#define FD_COPY(dst, src)                 \
do {                                      \
   memcpy((dst), (src), SOCKD_FD_SIZE()); \
} while (/* CONSTCOND */ 0)



#define ERRNOISNOFILE(errno) \
   ((errno) == EMFILE || (errno) == ENFILE)

#define ERRNOISRST(errno) \
   ((errno) == ECONNREFUSED || (errno) == ECONNRESET)

#define ERRNOISPREVIOUSPACKET(errno)                                           \
(     ERRNOISRST(errno)                                                        \
   || ERRNOISNOROUTE(errno)   /* Linux ... */                                  \
   || ERRNOISACCES(errno)     /* Linux ... */                                  \
   || (errno) == EMSGSIZE     /* Linux ... */                                  \
   || (errno) == ETIMEDOUT                                                     \
)

#define ERRNOISTMP(errno)      \
   (  (errno) == EAGAIN        \
   || (errno) == EWOULDBLOCK   \
   || (errno) == EINTR         \
   || (errno) == ENOBUFS       \
   || (errno) == ENOMEM        \
   || (errno) == ENOMSG)

#define ERRNOISACCES(errno) ((errno) == EPERM || (errno) == EACCES)

#define ERRNOISNOROUTE(errno) \
   ((errno) == ENETUNREACH || (errno) == EHOSTUNREACH || (errno) == ENETDOWN)

#define ERRNOISNETWORK(errno) (\
   ERRNOISNOROUTE(errno)       \
|| ERRNOISRST(errno)           \
)

#define PORTISRESERVED(port)   \
   (ntohs((port)) != 0 && ntohs((port)) < IPPORT_RESERVED)

#define IPADDRISBOUND(addr) \
(TOSA((addr))->sa_family == AF_UNSPEC ?                                        \
   0 : (TOSA((addr))->sa_family == AF_INET ?                                   \
         (TOIN((addr))->sin_addr.s_addr != htonl(INADDR_ANY))                  \
      :  (memcmp(TOIN6((addr))->sin6_addr.s6_addr,                             \
                 &in6addr_any,                                                 \
                 sizeof(in6addr_any)) != 0))                                   \
)

#define PORTISBOUND(addr) \
(TOSA((addr))->sa_family == AF_UNSPEC ?                                        \
   0 : (TOSA((addr))->sa_family == AF_INET ?                                   \
        (ntohs(TOIN((addr))->sin_port) != 0)                                   \
      : (ntohs(TOIN6((addr))->sin6_port)) != 0)                                \
)

#define ADDRISBOUND(addr) \
   (IPADDRISBOUND((addr)) && PORTISBOUND((addr)))

#define SOCKSHOSTISNOTBOUND(host)                                              \
  ((host)->port == htons(0) || !SOCKSHOST_ADDRISBOUND(host))

#define SOCKSHOSTISBOUND(host)  (!(SOCKSHOSTISNOTBOUND((host))))

#define SOCKSHOST_ADDRISBOUND(host)                                            \
(  ((host)->atype == SOCKS_ADDR_DOMAIN && *host->addr.domain != NUL)           \
|| ((host)->atype == SOCKS_ADDR_IPV4                                           \
   && (host)->addr.ipv4.s_addr != htonl(INADDR_ANY))                           \
|| ((host)->atype == SOCKS_ADDR_IPV6                                           \
   && memcmp(&(host)->addr.ipv6, &in6addr_any, sizeof(in6addr_any))) != 0)

#define RULEPORT_START(addr, protocol) (                                       \
   ((protocol) == SOCKS_TCP ? (addr)->port.tcp : (addr)->port.udp))

#if HAVE_SOCKADDR_STORAGE_SS_LEN

#define SET_SOCKADDRLEN(ss, len)       \
do {                                   \
   ((ss)->ss_len = (len));             \
} while (/* CONSTCOND */ 0)

#else /* !HAVE_SOCKADDR_STORAGE_SS_LEN */

#define SET_SOCKADDRLEN(ss, len)

#endif /* !HAVE_SOCKADDR_STORAGE_SS_LEN */

#define SET_SOCKADDR(sa, family)                                               \
do {                                                                           \
   ((sa)->ss_family = (family));                                               \
   SET_SOCKADDRLEN((sa), salen((family)));                                     \
} while (/* CONSTCOND */ 0)

#define SET_SOCKADDRPORT(sa, port)                                             \
do {                                                                           \
   switch ((sa)->ss_family) {                                                  \
      case AF_INET:                                                            \
         (TOIN(sa))->sin_port   = (port);                                      \
         break;                                                                \
                                                                               \
      case AF_INET6:                                                           \
         (TOIN6(sa))->sin6_port = (port);                                      \
         break;                                                                \
                                                                               \
      default:                                                                 \
         SERRX((sa)->ss_family);                                               \
   }                                                                           \
} while (/* CONSTCOND */ 0)


#define GET_SOCKADDRPORT(sa)                                                   \
   (((sa)->ss_family) == AF_INET ?                                             \
         TOCIN(sa)->sin_port : TOCIN6(sa)->sin6_port)                          \

#define SET_SOCKADDRADDR(sa, addr)                                             \
do {                                                                           \
   switch ((sa)->ss_family) {                                                  \
      case AF_INET:                                                            \
         memcpy(&(TOIN(sa))->sin_addr, addr, sizeof(TOIN(sa))->sin_addr);      \
         break;                                                                \
                                                                               \
      case AF_INET6:                                                           \
         memcpy(&(TOIN6(sa))->sin6_addr, addr, sizeof(TOIN6(sa))->sin6_addr);  \
         break;                                                                \
                                                                               \
      default:                                                                 \
         SERRX((sa)->ss_family);                                               \
   }                                                                           \
} while (/* CONSTCOND */ 0)


#define GET_SOCKADDRADDR(sa)                                                   \
   (((sa)->ss_family) == AF_INET ?                                             \
         ((const void *)&(TOCIN(sa)->sin_addr))                                \
      :  ((const void *)&(TOCIN6(sa)->sin6_addr)))                             \



#define ELEMENTS(array) (sizeof(array) / sizeof(array[0]))

#define OCTETIFY(a) ((a) &= 0xff)
/*
 * Note that the argument will be truncated, not just the return value.
 */


/*
 * Stuff for messages between our processes.
 */

/* padding for each message between mother/child, including separation. */
#define SENDMSG_PADBYTES   (sizeof(long) * 64) /* just a guess. */


/*
 * macros to manipulate ancillary data depending on if we're on sysv or BSD.
 */

/*
 * Modern CMSG alignment macros. Use them if the platform has them,
 * if not we get the default behavior.
 */

#if HAVE_CMSGHDR

#if !HAVE_CMSG_LEN
#define CMSG_LEN(len) (sizeof(struct cmsghdr) + (len))
#endif /* !HAVE_CMSG_LEN */

#if !HAVE_CMSG_SPACE
#define CMSG_SPACE(len) (sizeof(struct cmsghdr) + (len))
#endif /* !HAVE_CMSG_SPACE */

#else /* HAVE_CMSGHDR */

#if !HAVE_CMSG_LEN
#define CMSG_LEN(len) (len)
#endif /* !HAVE_CMSG_LEN */

#if !HAVE_CMSG_SPACE
#define CMSG_SPACE(len) (len)
#endif /* !HAVE_CMSG_SPACE */

#endif /* HAVE_CMSGHDR */

/*
 * allocate memory for a control message of size "size".  "name" is the
 * name of the allocated memory.
 */
#if HAVE_CMSGHDR

#define CMSG_AALLOC(name, size)           \
   union {                                \
      char   cmsgmem[CMSG_SPACE(size)];   \
      struct cmsghdr align;               \
   } __CONCAT3(_, name, mem) = { { 0 } };    /* cleared to appease valgrind */ \
   struct cmsghdr *name = (struct cmsghdr *)__CONCAT3(_, name, mem).cmsgmem;

#else /* !HAVE_CMSGHDR */

#define CMSG_AALLOC(name, size)           \
   char name[(size)] = NUL;

#endif /* !HAVE_CMSGHDR */


/*
 * Returns the size of the previously allocated control message named
 * "name"
 */
#if HAVE_CMSGHDR
#define CMSG_MEMSIZE(name) (sizeof(__CONCAT3(_, name, mem)))
#else /* !HAVE_CMSGHDR */
#define CMSG_MEMSIZE(name) (sizeof((name)))
#endif /* HAVE_CMSGHDR */

/*
 * Verifies length of received control message.
 *
 * Final padding might not be present in received message,
 * expected length can be either value of CMSG_SPACE() or CMSG_LEN().
 */
#define CMSG_RCPTLEN_ISOK(msg, datalen)                                        \
    ((datalen) == 0 ? ((size_t)(CMSG_TOTLEN(msg) == 0))                        \
            :   ((size_t)CMSG_TOTLEN((msg)) == (size_t)(CMSG_SPACE((datalen))) \
              || (size_t)CMSG_TOTLEN((msg)) == (size_t)(CMSG_LEN((datalen)))))

/*
 * Returns the control data member of "msg".
 */
#if HAVE_CMSGHDR
/*
 * cast is necessary on AIX, due to buggy headers there?
 * needs additional testing on AIX, disable for now.
 */
#define CMSG_CONTROLDATA(msg)   ((msg).msg_control)
#else /* !HAVE_CMSGHDR */
#define CMSG_CONTROLDATA(msg)   ((msg).msg_accrights)
#endif /* HAVE_CMSGHDR */

/*
 * add "object" to "data".  "object" is the object to add to "data" at
 * offset "offset".
 */
#if HAVE_CMSGHDR
#define CMSG_ADDOBJECT(object, data, offset)                         \
   do                                                                \
      memcpy(CMSG_DATA(data) + (offset), &(object), sizeof(object)); \
   while (/* CONSTCOND */ 0)
#else /* !HAVE_CMSGHDR */
#define CMSG_ADDOBJECT(object, data, offset)                         \
   do                                                                \
      memcpy(data + (offset), &(object), sizeof((object)));          \
   while (/* CONSTCOND */ 0)
#endif /* !HAVE_CMSGHDR */

/*
 * get a object from control data "data".
 * "object" is the object to fill with data gotten from "data" at offset
 * "offset".
 */
#if HAVE_CMSGHDR
#define CMSG_GETOBJECT(object, data, offset)                               \
   do                                                                      \
      memcpy(&(object), CMSG_DATA((data)) + (offset), sizeof((object)));   \
   while (/* CONSTCOND */ 0)
#else /* !HAVE_CMSGHDR */
#define CMSG_GETOBJECT(object, data, offset)                               \
   do                                                                      \
      memcpy(&(object), ((data) + (offset)), sizeof((object)));            \
   while (/* CONSTCOND */ 0)
#endif /* !HAVE_CMSGHDR */

/*
 * Sets up "object" for sending a control message of size "size".
 * "controlmem" is the memory the control message is stored in.
 *
 * CMSG_SPACE() rather than CMSG_LEN() apparently correct value
 * for msg_controllen.
 */
#if HAVE_CMSGHDR
#define CMSG_SETHDR_SEND(object, controlmem, size)                             \
do {                                                                           \
   if (size == 0) {                                                            \
      object.msg_control      = NULL;                                          \
      object.msg_controllen   = 0;                                             \
   }                                                                           \
   else {                                                                      \
      bzero(controlmem, sizeof(*controlmem));                                  \
                                                                               \
      controlmem->cmsg_level  = SOL_SOCKET;                                    \
      controlmem->cmsg_type   = SCM_RIGHTS;                                    \
      controlmem->cmsg_len    = CMSG_LEN(size);                                \
                                                                               \
      object.msg_control      = (caddr_t)controlmem;                           \
      object.msg_controllen   = (size) == 0 ? 0 : CMSG_SPACE((size));          \
  }                                                                            \
} while (/* CONSTCOND */ 0)
#else /* !HAVE_CMSGHDR */
#define CMSG_SETHDR_SEND(object, controlmem, size)                             \
do {                                                                           \
  object.msg_accrights      = (caddr_t)controlmem;                             \
  object.msg_accrightslen   = (size);                                          \
} while (/* CONSTCOND */ 0)
#endif /* !HAVE_CMSGHDR */

/*
 * Sets up "object" for receiving a control message of size "size".
 * "controlmem" is the memory set aside for the control message.
 */
#if HAVE_CMSGHDR
#define CMSG_SETHDR_RECV(object, controlmem, size)             \
   do {                                                        \
      object.msg_control      = (caddr_t)controlmem;           \
      object.msg_controllen   = (size);                        \
   } while (/* CONSTCOND */ 0)
#else /* !HAVE_CMSGHDR */
#define CMSG_SETHDR_RECV(object, controlmem, size)             \
   do {                                                        \
      object.msg_accrights      = (caddr_t)controlmem;         \
      object.msg_accrightslen   = (size);                      \
   } while (/* CONSTCOND */ 0)
#endif /* !HAVE_CMSGHDR */

/* returns length of control data actually sent. */
#if HAVE_CMSGHDR
#define CMSG_GETLEN(msg)   ((msg).msg_controllen - CMSG_LEN(0))
#else
#define CMSG_GETLEN(msg)   ((msg).msg_accrightslen)
#endif /* HAVE_CMSGHDR */

#if HAVE_CMSGHDR
#define CMSG_TOTLEN(msg)   ((msg).msg_controllen)
#else
#define CMSG_TOTLEN(msg)   ((msg).msg_accrightslen)
#endif /* HAVE_CMSGHDR */


/* the size of a UDP header "packet" (no padding) */
#define HEADERSIZE_UDP(packet) (                                               \
   sizeof((packet)->flag) + sizeof((packet)->frag)                             \
   + sizeof((packet)->host.atype) + sizeof((packet)->host.port)                \
   + (ADDRESSIZE_V5(packet)))


/*
 * returns the length of the current address field in socks packet "packet".
 * "packet" can be one of pointer to response_t, request_t or udpheader_t.
 */
#define ADDRESSIZE(packet) (                                                   \
     ((packet)->version == SOCKS_V4 ?                                          \
     (ADDRESSIZE_V4(packet)) : (ADDRESSIZE_V5(packet))))

/*
 *   version specifics
 */
#define ADDRESSIZE_V5(packet) (                                                \
  (packet)->host.atype == SOCKS_ADDR_IPV4 ?                                    \
        sizeof((packet)->host.addr.ipv4)                                       \
      : (packet)->host.atype  == (unsigned char)SOCKS_ADDR_IPV6 ?              \
            sizeof((packet)->host.addr.ipv6.ip)                                \
          : (strlen((packet)->host.addr.domain) + 1))

#define ADDRESSIZE_V4(packet) (                                                \
   (packet)->atype == SOCKS_ADDR_IPV4 ?                                        \
   sizeof((packet)->addr.ipv4) : (strlen((packet)->addr.host) + 1))


/*
 * This is for Rgethostbyname() support for clients without access to
 * DNS.
 * FAKEIP_START is the first address in the range of "fake" IP addresses,
 * FAKEIP_END is the last.
 * There can thus be FAKEIP_END - FAKEIP_START number of fake IP addresses
 * supported per program.
 *
 * INADDR_NONE and INADDR_ANY may not be part of the range.
 */
#define FAKEIP_START 0x00000001
#define FAKEIP_END   0x000000ff

#define PROXY_UPNP                  3
#define PROXY_UPNPs                 "UPNP"
#define PROXY_BROADCASTs            "broadcast"    /* subset of upnp. */
#define PROXY_SOCKS_V4               4
#define PROXY_SOCKS_V4s              "socks_v4"
#define PROXY_SOCKS_V4REPLY_VERSION  0
#define PROXY_SOCKS_V5               5
#define PROXY_SOCKS_V5s              "socks_v5"
#define PROXY_DIRECT                 6
#define PROXY_DIRECTs               "direct"
#define PROXY_HTTP_10               7
#define PROXY_HTTP_10s              "HTTP/1.0"
#define PROXY_HTTP_11               8
#define PROXY_HTTP_11s              "HTTP/1.1"

/* sub negotiation. */
#define SOCKS_UNAMEVERSION              1
#define SOCKS_GSSAPI_VERSION            1
#define SOCKS_GSSAPI_AUTHENTICATION     1
#define SOCKS_GSSAPI_ENCRYPTION         2
#define SOCKS_GSSAPI_PACKET             3
#define SOCKS_GSSAPI_CLEAR              0
#define SOCKS_GSSAPI_INTEGRITY          1
#define SOCKS_GSSAPI_CONFIDENTIALITY    2
#define SOCKS_GSSAPI_PERMESSAGE         3

/* authentication METHOD values. */
#define AUTHMETHOD_NOTSET      -1
#define AUTHMETHOD_NOTSETs      "notset"
#define AUTHMETHOD_NONE         0
#define AUTHMETHOD_NONEs        "none"
#define AUTHMETHOD_GSSAPI       1
#define AUTHMETHOD_GSSAPIs      "gssapi"
#define AUTHMETHOD_UNAME        2
#define AUTHMETHOD_UNAMEs      "username"

/* X'03' to X'7F' IANA ASSIGNED                  */

/* X'80' to X'FE' RESERVED FOR PRIVATE METHODS   */

#define AUTHMETHOD_NOACCEPT   255
#define AUTHMETHOD_NOACCEPTs   "<no acceptable method>"

/* non-standard methods.  Must be > AUTHMETHOD_NOACCEPT. */
#define AUTHMETHOD_RFC931          (AUTHMETHOD_NOACCEPT + 1)
#define AUTHMETHOD_RFC931s         "rfc931"

#define AUTHMETHOD_PAM_ANY         (AUTHMETHOD_RFC931 + 1)
#define AUTHMETHOD_PAM_ANYs        "pam.any"

#define AUTHMETHOD_PAM_ADDRESS     (AUTHMETHOD_PAM_ANY + 1)
#define AUTHMETHOD_PAM_ADDRESSs    "pam.address"

#define AUTHMETHOD_PAM_USERNAME    (AUTHMETHOD_PAM_ADDRESS + 1)
#define AUTHMETHOD_PAM_USERNAMEs   "pam.username"

#define AUTHMETHOD_BSDAUTH     (AUTHMETHOD_PAM_USERNAME + 1)
#define AUTHMETHOD_BSDAUTHs    "bsdauth"

#define AUTHMETHOD_MAX         (AUTHMETHOD_BSDAUTH)

#define MAXMETHODSTRING      (MAX(sizeof(AUTHMETHOD_NONEs),             \
                              MAX(sizeof(AUTHMETHOD_GSSAPIs),           \
                              MAX(sizeof(AUTHMETHOD_UNAMEs),            \
                              MAX(sizeof(AUTHMETHOD_RFC931s),           \
                              MAX(sizeof(AUTHMETHOD_PAM_ANYs),          \
                              MAX(sizeof(AUTHMETHOD_PAM_ADDRESSs),      \
                              MAX(sizeof(AUTHMETHOD_PAM_USERNAMEs),     \
                              sizeof(AUTHMETHOD_BSDAUTHs)))))))))

/* number of supported methods. */
#define METHODS_KNOWN  (  1  /* NONE      */   \
                        + 1  /* GSSAPI    */   \
                        + 1  /* UNAME     */   \
                        + 1  /* RFC931    */   \
                        + 1  /* PAM       */   \
                        + 1) /* BSDAUTH   */

#define MAXMETHODS     (255)  /*
                               * max number of methods we can be offered, and
                               * potentially support.
                               */

/*
 *  Response commands/codes
 */
#define SOCKS_CONNECT            1
#define SOCKS_CONNECTs           "connect"
#define SOCKS_BIND               2
#define SOCKS_BINDs              "bind"
#define SOCKS_UDPASSOCIATE       3
#define SOCKS_UDPASSOCIATEs      "udpassociate"

/* pseudo commands */

#define SOCKS_COMMANDEND         0xff

#define SOCKS_BINDREPLY          (SOCKS_COMMANDEND + 1)
#define SOCKS_BINDREPLYs         "bindreply"

#define SOCKS_UDPREPLY           (SOCKS_BINDREPLY + 1)
#define SOCKS_UDPREPLYs          "udpreply"

/* misc. stuff */
#define SOCKS_ACCEPT             (SOCKS_UDPREPLY + 1)
#define SOCKS_ACCEPTs            "accept"

#define SOCKS_DISCONNECT         (SOCKS_ACCEPT + 1)
#define SOCKS_DISCONNECTs        "disconnect"

#define SOCKS_BOUNCETO            (SOCKS_DISCONNECT + 1)
#define SOCKS_BOUNCETOs           "bounce-to"

#define SOCKS_HOSTID              (SOCKS_BOUNCETO + 1)
#define SOCKS_HOSTIDs             "hostid"

#define SOCKS_UNKNOWN            (SOCKS_HOSTID + 1)
#define SOCKS_UNKNOWNs           "unknown"


/* reply field values */
#define SOCKS_SUCCESS         0x00
#define SOCKS_FAILURE         0x01
#define SOCKS_NOTALLOWED      0x02
#define SOCKS_NETUNREACH      0x03
#define SOCKS_HOSTUNREACH     0x04
#define SOCKS_CONNREFUSED     0x05
#define SOCKS_TTLEXPIRED      0x06
#define SOCKS_CMD_UNSUPP      0x07
#define SOCKS_ADDR_UNSUPP     0x08

/* version 4 codes. */
#define SOCKSV4_SUCCESS        90
#define SOCKSV4_FAIL           91
#define SOCKSV4_NO_IDENTD      92
#define SOCKSV4_BAD_ID         93

/* http stuff. */
#define HTTP_SUCCESS           200
#define HTTP_NOTALLOWED        401
#define HTTP_FORBIDDEN         403
#define HTTP_PROXYAUTHREQUIRED 407
#define HTTP_HOSTUNREACH       504
#define HTTP_FAILURE           501
#define SOCKD_HTTP_PORT        80

/* upnp stuff. */
#define UPNP_DISCOVERYTIME_MS              (1000)
#define UPNP_IP_TTL                        (2)
#define DEFAULT_SSDP_BROADCAST_IPV4ADDR    "239.255.255.250"
#define DEFAULT_SSDP_PORT                  (1900)

/* return codes from UPNP_GetValidIGD(). */
#define UPNP_NO_IGD           (0)
#define UPNP_CONNECTED_IGD    (1)
#define UPNP_DISCONNECTED_IGD (2)
#define UPNP_UNKNOWN_DEVICE   (3)

#define UPNP_SUCCESS          (1)
#define UPNP_FAILURE          (2)

/* flag _bits_ */
#define SOCKS_INTERFACEREQUEST   0x01
#define SOCKS_USECLIENTPORT      0x04

/* subcommands */
#define SOCKS_INTERFACEDATA      0x01

#define SOCKS_RECV      0
#define SOCKS_SEND      1

/* offsets into authentication packet */
#define AUTH_VERSION         (0)   /* version of method packet.               */

/* request */
#define AUTH_NMETHODS        (1)   /* offset of number of methods offered.    */
#define AUTH_FIRSTMETHOD     (2)   /* offset of first method offered.         */

/* reply */
#define AUTH_SELECTEDMETHOD  (1)  /* offset for selected method in response. */

/* offsets into username/password negotiation packet */
#define UNAME_VERSION      (0)
#define UNAME_STATUS       (1)


/* uname status values. */
#define UNAME_STATUS_ISOK    (0)
#define UNAME_STATUS_ISNOK   (1)

/* offsets into gssapi negotiation packet */
#define GSSAPI_VERSION          0
#define GSSAPI_STATUS           1
#define GSSAPI_TOKEN_LENGTH     2
#define GSSAPI_TOKEN            4


#define GSSAPI_CLEAR            0
#define GSSAPI_INTEGRITY        1
#define GSSAPI_CONFIDENTIALITY  2

#define GSS_REQ_INT             0
#define GSS_REQ_CONF            1

#define SOCKS_IPV6_ALEN          16
#define IPV6_NETMASKBITS         (128)
#define IPV4_NETMASKBITS         (32)
#define IPV4_FULLNETMASK         (0xffffffff)

#define IP6_ELEMENTS(ip6)     \
(ip6)->s6_addr[0],            \
(ip6)->s6_addr[1],            \
(ip6)->s6_addr[2],            \
(ip6)->s6_addr[3],            \
(ip6)->s6_addr[4],            \
(ip6)->s6_addr[5],            \
(ip6)->s6_addr[6],            \
(ip6)->s6_addr[7],            \
(ip6)->s6_addr[8],            \
(ip6)->s6_addr[9],            \
(ip6)->s6_addr[10],           \
(ip6)->s6_addr[11],           \
(ip6)->s6_addr[12],           \
(ip6)->s6_addr[13],           \
(ip6)->s6_addr[14],           \
(ip6)->s6_addr[15]

#define IP6_FMTSTR "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"

#define BINDEXTENSION_IPADDR     (0xffffffff)



/*
 * hostid related defines
 */

/* socket option hostid types */
#define SOCKS_HOSTID_TYPE_NONE 0
#define SOCKS_HOSTID_TYPE_TCP_IPA 1

#if SOCKS_HOSTID_TYPE == SOCKS_HOSTID_TYPE_NONE
#define HAVE_SOCKS_HOSTID (0)
#else
#define HAVE_SOCKS_HOSTID (1)
#endif

/* supported commands/command strings for parsing */
#define SOCKS_HOSTID_NONE 0
#define SOCKS_HOSTID_NONE_SYMNAME "none"
#define SOCKS_HOSTID_PASS 1
#define SOCKS_HOSTID_PASS_SYMNAME "pass"
#define SOCKS_HOSTID_ADDCLIENT 2
#define SOCKS_HOSTID_ADDCLIENT_SYMNAME "add-client"
#define SOCKS_HOSTID_SETCLIENT 3
#define SOCKS_HOSTID_SETCLIENT_SYMNAME "set-client"

typedef enum { NONESETIF = 0, INTERNALIF, EXTERNALIF } interfaceside_t;

enum operator_t { none = 0, eq, neq, ge, le, gt, lt, range };
typedef enum { dontcare, istrue, isfalse } value_t;
typedef enum { username, udpreplies, tcpreplies, replies } methodinfo_t;
typedef enum { softlimit, hardlimit } limittype_t;
typedef enum { type_global, type_rule, type_route } opttype_t;


#define SOCKS_ADDR_NOTSET   (0)
#define SOCKS_ADDR_IPV4     (1)
#define SOCKS_ADDR_IFNAME   (2)
#define SOCKS_ADDR_DOMAIN   (3)
#define SOCKS_ADDR_IPV6     (4)
#define SOCKS_ADDR_URL      (5)
#define SOCKS_ADDR_IPVANY   (6) /* for 0/0 address matching ipv4 and ipv6. */

typedef enum { object_none = 0,     /* no object set. */
               object_sockaddr,
               object_sockshost,
               object_crule,
               object_hrule,
               object_srule,
               object_route,
               object_monitor } objecttype_t;


#define MAXLOGLEVELLEN           (sizeof("warning"))
typedef struct {
   const char name[MAXLOGLEVELLEN];
   const int  value;
} loglevel_t;


typedef struct {
   /*
    * if we mark a route/proxy server as bad, how many seconds to wait
    * until we expire the badmarking so it will be tried again for new
    * connections.  A value of zero means never.
    */
   time_t badexpire;

   /*
    * how many times a route can fail before being marked as bad.
    * A value of zero means it will never be marked as bad.
    */
   size_t maxfail;
} routeoptions_t;

typedef struct {
   int           type;        /* type of logging (where to).                  */

   char          **fnamev;    /* name of file, if logging to file.            */
   unsigned char *createdv;   /* did we create this logfile ourselves?        */
   int           *filenov;    /* if logging is to file, the file descriptor.  */
   size_t        filenoc;     /* number of files.                             */

   int           facility;    /* if logging to syslog, this is the facility.  */
   char          facilityname[MAXFACILITYNAMELEN]; /* facilityname.           */
} logtype_t;



/* extensions supported by us. */
typedef struct {
   unsigned char bind;      /* use bind extension? */
} extension_t;

typedef enum { TIMEOUT_NOTSET = 0,
               TIMEOUT_NEGOTIATE,
               TIMEOUT_CONNECT,
               TIMEOUT_IO,
               TIMEOUT_TCP_FIN_WAIT,
               TIMEOUT_NETWORKTEST
} timeouttype_t;

typedef struct {
   /*
    * type should match the struct timeval.tv_sec used by select(2).
    * POSIX says it's time_t.
    */

   time_t connect;   /* how long to wait before giving up connect(2). */
#if !SOCKS_CLIENT
   time_t negotiate; /* how long negotiation can last.                */
   time_t tcpio;     /* how long session can last without i/o.        */
   time_t udpio;     /* how long session can last without i/o.        */

   time_t tcp_fin_wait; /* how long to wait after one end closes.     */
#endif /* !SOCKS_CLIENT */
} timeout_t;

/* method rfc931 */
typedef struct {
   unsigned char   name[MAXNAMELEN];
} authmethod_rfc931_t;

/* method pam. */
typedef struct {
   char            servicename[MAXNAMELEN];   /* servicename to use with pam. */
   unsigned char   name[MAXNAMELEN];
   unsigned char   password[MAXPWLEN];
} authmethod_pam_t;

/* method bsdauth. */
typedef struct {
   char            style[MAXNAMELEN];   /* style to use. */
   unsigned char   name[MAXNAMELEN];
   unsigned char   password[MAXPWLEN];
} authmethod_bsd_t;

/* method username */
typedef struct {
   unsigned char   version;
   unsigned char   name[MAXNAMELEN];
   unsigned char   password[MAXPWLEN];
} authmethod_uname_t;

#if HAVE_GSSAPI
typedef struct {
       unsigned char nec;
       unsigned char clear;
       unsigned char integrity;
       unsigned char confidentiality;
       unsigned char permessage;
} gssapi_enc_t;

#ifndef BUFSIZ
#define BUFSIZ 1024
#endif /* !BUFSIZ */
typedef struct {
    int            read;
    int            rpos;
    int            wpos;
    int            isbuffered;
    unsigned char  rbuffer[GSSAPI_HLEN + MAXGSSAPITOKENLEN];
    unsigned char  wbuffer[BUFSIZ];
} gssapi_buf_t;

typedef struct {
   int                 wrap;        /* gssapi-wrapped, or clear?              */
   gss_ctx_id_t        id;          /* gssapi context id.                     */
   int                 protection;  /* selected protection mechanism.         */

   OM_uint32           maxgssdata;  /* max length of gss data pre-encoding.   */
   size_t              gssoverhead; /*
                                     * overhead in bytes of gssapi given the
                                     * current mechanism/context/etc.
                                     * Don't know what the practical max
                                     * actually is, so this contains the
                                     * max overhead experienced so far.
                                     */
} gssapi_state_t;

/* method gssapi */
typedef struct {
       char           servicename[MAXNAMELEN];
       char           keytab[MAXNAMELEN];
       unsigned char  name[MAXNAMELEN];
       gssapi_enc_t   encryption;                  /* encryption details      */
       gssapi_state_t state;                       /* gssapi state details    */
} authmethod_gssapi_t;

#endif /* HAVE_GSSAPI */


/* this must be big enough to hold a complete method request. */
typedef struct {
   int                  method;                /* method in use.              */

   /*
    * Methods authenticated at some stage of the process.
    */
   int                  methodv[METHODS_KNOWN];
   size_t               methodc;  /* number of methods authenticated. */

   /*
    * Methods that failed authentication at some stage of the process.
    */
   int                  badmethodv[METHODS_KNOWN];
   size_t               badmethodc;  /* number of methods that failed. */

   union {
      authmethod_uname_t   uname;

#if HAVE_GSSAPI
      authmethod_gssapi_t  gssapi;
#endif /* HAVE_GSSAPI */
#if HAVE_LIBWRAP
      authmethod_rfc931_t  rfc931;
#endif /* HAVE_LIBWRAP */
#if HAVE_PAM
      authmethod_pam_t     pam;
#endif /* HAVE_PAM */
#if HAVE_BSDAUTH
      authmethod_bsd_t     bsd;
#endif /* HAVE_BSDAUTH */
   } mdata;
} authmethod_t;

typedef union {
   int                       int_val;
   struct linger             linger_val;
   struct timeval            timeval_val;
   struct in_addr            in_addr_val;
   unsigned char             uchar_val;
   struct sockaddr_storage   sockaddr_val;
   struct ipoption           ipoption_val;

#if HAVE_TCP_IPA
   struct tcp_ipa            option28_val;
#endif /* HAVE_TCP_IPA */
} socketoptvalue_t;

/*
 * make sure to keep this in sync with the size calculation in
 * setusersockoptions().
 */
typedef enum { int_val = 1, linger_val, timeval_val, in_addr_val, uchar_val,
               sockaddr_val, ipoption_val, option28_val } socketoptvalue_type_t;

#if HAVE_TCP_IPA
#define SOCKETOPTVALUETYPE2SIZE(type)                                          \
   ((type) == int_val      ? sizeof(int) :                                     \
    (type) == linger_val   ? sizeof(struct linger) :                           \
    (type) == timeval_val  ? sizeof(struct timeval) :                          \
    (type) == in_addr_val  ? sizeof(struct in_addr) :                          \
    (type) == uchar_val    ? sizeof(u_char) :                                  \
    (type) == sockaddr_val ? sizeof(struct sockaddr_storage) :                         \
    (type) == ipoption_val ? sizeof(struct ipoption) :                         \
    (type) == option28_val ? sizeof(struct tcp_ipa)  :                         \
    0)
#else /* !HAVE_TCP_IPA */

#define SOCKETOPTVALUETYPE2SIZE(type)                                          \
   ((type) == int_val      ? sizeof(int) :                                     \
    (type) == linger_val   ? sizeof(struct linger) :                           \
    (type) == timeval_val  ? sizeof(struct timeval) :                          \
    (type) == in_addr_val  ? sizeof(struct in_addr) :                          \
    (type) == uchar_val    ? sizeof(u_char) :                                  \
    (type) == sockaddr_val ? sizeof(struct sockaddr_storage) :                         \
    (type) == ipoption_val ? sizeof(struct ipoption) :                         \
    0)
#endif /* !HAVE_TCP_IPA */

#define SOCKETOPT_PRE     (0x1)
#define SOCKETOPT_POST    (0x2)
#define SOCKETOPT_ANYTIME (0x4)
#define SOCKETOPT_ALL     (SOCKETOPT_PRE | SOCKETOPT_POST | SOCKETOPT_ANYTIME)

typedef enum { preonly = 1, anytime, postonly, invalid } sockopt_calltype_t;
typedef struct {
   size_t                optid;   /* option identifier                        */
   socketoptvalue_type_t opttype; /* socket option argument type              */
   int                   value;   /* value of SO_foo define                   */
   int                   level;   /* protocol level option applies to         */

   unsigned char         ipv4_on; /* settable for ipv4?                       */
   unsigned char         ipv6_on; /* settable for ipv6?                       */

   /*
    * XXX currently assumed that getsockopt() only called for options
    *     where shift/mask is set
    */
   sockopt_calltype_t calltype;   /* when option can be set.                  */
   unsigned int       shift;      /* number of bits to shift argument value.  */
   unsigned int       mask;       /* if set, mask specifying valid values.    */
   unsigned char      dodup;      /* whether option should be duplicated      */
   unsigned char      needpriv;   /* whether privileges are required          */
   char               name[SOCKOPTNAME_MAXLEN]; /* optionname as string.      */
} sockopt_t;

typedef struct {
   size_t optid;                  /* sockopt_t id symbol is valid for         */
   socketoptvalue_t symval;       /* value of symbolic constant               */
   char *name;                    /* textual representation of constant value */
} sockoptvalsym_t;

typedef struct {
   const sockopt_t       *info;          /* NULL if unknown option.           */
   int                   level;          /*
                                          * socket level to set option at.
                                          * Not necessarily the same as
                                          * info->level as we allow the user
                                          * to specify e.g. "tcp" instead
                                          * of level sol_socket, indicating
                                          * the option should only be set
                                          * for tcp sockets.  The value
                                          * in "info" is the value we need
                                          * use when setting the option.
                                          */

   int                   optname;        /* numeric of option to set.         */
   socketoptvalue_t      optval;         /* value set.                    */
   socketoptvalue_type_t opttype;        /* socket option argument type.      */

   unsigned char         isinternalside; /* option for the internal side?     */
} socketoption_t;


union socksaddr_t {
   char               domain[MAXHOSTNAMELEN];
   char               urlname[MAXURLLEN];
   char               ifname[MAXIFNAMELEN];
   struct in_addr     ipv4;
   struct {
      struct in6_addr  ip;
      uint32_t         scopeid;
   } ipv6;
};

typedef struct sockshost_t {
   unsigned char        atype;
   union socksaddr_t    addr;
   in_port_t            port;
} sockshost_t;

typedef struct {
   unsigned char httpconnect;    /* session is the result of a http connect. */
} requestflags_t;

typedef struct request_t {
   authmethod_t   *auth;   /* pointer to level above. */
   unsigned char  command;
   unsigned char  flag;
   sockshost_t    host;
   int            protocol;
   unsigned char  version;

   requestflags_t flags;
} request_t;


typedef struct {
   unsigned char         version;

   union {
      unsigned char         socks;
      unsigned char         upnp;
      unsigned short        http;
   } reply;

   unsigned char  flag;
   sockshost_t    host;
   authmethod_t   *auth;   /* pointer to level above. */
} response_t;

/* encapsulation for UDP packets. */
typedef struct {
   unsigned char flag[2];
   unsigned char frag;
   sockshost_t   host;
} udpheader_t;

typedef struct {
   unsigned char tcp;
   unsigned char udp;
} protocol_t;


typedef struct {
   unsigned char bind;
   unsigned char connect;
   unsigned char udpassociate;

   /* not real commands as per standard, but they have their use. */
   unsigned char bindreply;      /* reply to bind command.   */
   unsigned char udpreply;       /* reply to UDP packet.     */
} command_t;


typedef struct {
   unsigned char direct;
   unsigned char socks_v4;
   unsigned char socks_v5;
   unsigned char http;
   unsigned char upnp;
} proxyprotocol_t ;

/* values in parentheses designate "don't care" values when searching.  */
typedef struct {
   int                     acceptpending; /* a accept pending?      (-1)      */
   authmethod_t            auth;          /* authentication in use.           */
   int                     command;       /* command (-1)                     */
   int                     err;           /* if request failed, errno.        */
#if HAVE_GSSAPI
   int                     gssimportneeded;
   gss_buffer_desc         gssapistate;   /* if gssimportneeded, data for it. */
   unsigned char           gssapistatemem[MAX_GSS_STATE];
#endif /* HAVE_GSSAPI */
   int                     inprogress;    /* operation in progress? (-1)      */
   unsigned char           issyscall;     /* started out as a real system call*/
   protocol_t              protocol;      /* protocol in use.                 */
   unsigned char           udpconnect;    /* connected UDP socket?            */
   int                     syscalldepth;
   int                     version;       /* version (-1)                     */
} socksstate_t;

typedef struct ruleaddr_t {
   unsigned char         atype;
   union {
      char               domain[MAXHOSTNAMELEN];

      char               ifname[MAXIFNAMELEN];

      struct {
         struct in_addr   ip;
         struct in_addr   mask;
      } ipv4;

      struct {
         struct in6_addr   ip;
         unsigned int      maskbits; /* host order. */
         uint32_t          scopeid;  /* host order. */
      } ipv6;

      struct {
         /*
          * both should always be zero as this is only meaningful for
          * a rule that should match all and any kind of ipaddress.
          */
         struct in_addr   ip;
         struct in_addr   mask;
      } ipvany;

   } addr;

   struct {
      in_port_t         tcp;      /* TCP portstart or field to operator on.   */
      in_port_t         udp;      /* UDP portstart or field to operator on.   */
   } port;
   in_port_t            portend;   /* only used if operator is range.         */
   enum operator_t      operator;  /* operator to compare ports via.          */
} ruleaddr_t;

#ifndef MINIUPNPC_URL_MAXSIZE
#define MINIUPNPC_URL_MAXSIZE (128)
#endif
typedef union {
   struct {
      char    controlurl[MINIUPNPC_URL_MAXSIZE];
      char    servicetype[MINIUPNPC_URL_MAXSIZE];
   } upnp;
} proxystate_t;

typedef struct linkedname_t {
   char                  *name;
   struct linkedname_t   *next;   /* next name in list.                       */
} linkedname_t;


#if HAVE_LDAP
typedef struct {
       linkedname_t *ldapurl;               /* name of ldap urls.      */
       linkedname_t *ldapbasedn;            /* name of ldap basedns.   */
       char         attribute[MAXNAMELEN];
       char         attribute_AD[MAXNAMELEN];
       char         certfile[MAXURLLEN];
       char         certpath[MAXURLLEN];
       int          debug;
       int          mdepth;
       char         domain[MAXNAMELEN];
       char         filter[MAXNAMELEN];
       char         filter_AD[MAXNAMELEN];
       char         keytab[MAXNAMELEN];
       int          port;
       int          portssl;

       unsigned char auto_off;
       unsigned char ssl;
       unsigned char certcheck;
       unsigned char keeprealm;
} ldap_t;
#endif /* HAVE_LDAP */



typedef struct {
   command_t        command;
   extension_t      extension;
   protocol_t       protocol;

   int              cmethodv[METHODS_KNOWN]; /* clientmethods to offer.       */
   size_t           cmethodc;                /* number of methods to offer.   */
   int              smethodv[METHODS_KNOWN]; /* socksmethods to offer.        */
   size_t           smethodc;                /* number of methods to offer.   */

   proxyprotocol_t  proxyprotocol;

#if HAVE_PAM
   char             pamservicename[MAXNAMELEN];
#endif /* HAVE_PAM */

#if HAVE_BSDAUTH
   char             bsdauthstylename[MAXNAMELEN];
#endif /* HAVE_BSDAUTH */

#if HAVE_GSSAPI
   char             gssapiservicename[MAXNAMELEN];
   char             gssapikeytab[MAXNAMELEN];
   gssapi_enc_t     gssapiencryption;       /* encryption status.      */
#endif /* HAVE_GSSAPI */

#if HAVE_LDAP
   ldap_t           ldap;
#endif

#if HAVE_LIBMINIUPNP
   proxystate_t     data;
#endif /* HAVE_LIBMINIUPNP */
} serverstate_t;

typedef struct {
   sockshost_t     addr;
   serverstate_t   state;
} gateway_t;


typedef struct {
   unsigned char     version;
                     /*
                      * Negotiated version.  Each request and
                      * response will also contain a version number, that
                      * is the version number given for that particular
                      * packet and should be checked to make sure it is
                      * the same as the negotiated version.
                      */
   request_t         req;
   response_t        res;
   gateway_t         gw;
   socksstate_t      state;
} socks_t;

enum portcmp { e_lt = 1, e_gt, e_eq, e_neq, e_le, e_ge, e_nil };



/*
 * for use in generic functions that take either reply or request
 * packets, include a field indicating what it is.
 */
#define SOCKS_REQUEST   0x1
#define SOCKS_RESPONSE  0x2

/*
 * This object is either used for straightforward buffering, or
 * in the case the data is gssapi-encapsulated, to handle gssapi-data.
 * In the case of simple, non-gssapi, buffering,
 * no further explanation is given; the len field simply holds
 * the number of bytes currently buffered.
 *
 * Next we describe how it is used in the case of gssapi.
 *
 * In the case of gssapi, the buffer is divided into two parts,
 * the first part holding not-encoded data, and the latter part
 * holding encoded data.
 *
 * The operation when reading is as follows:
 *    1) Read into buf as much data as is needed to be able to
 *       decode the data (in the case of gssapi, the whole token).
 *       While doing this, we keep incrementing "enclen", to indicate
 *       how much encoded data has been stored in the buffer.  "len"
 *       is not touch during this.
 *
 *    2) When 1) has completed, we replace the data in buf with
 *       the decoded version of data in "buf", reset "enclen", and
 *       set "len" to indicate how much decoded data is stored in the
 *       buffer.
 *
 *    3) On subsequent read operations on the socket corresponding to
 *       the data (s), return data from buf instead of reading it from
 *       the socket.
 *
 *    4) When all data in buf has been returned, clear the iobuffer.
 *
 * The operation when writing is more complicated, because
 * we can get multiple write requests that we fail to send down
 * to the socket buffer, which in sum may be bigger than the
 * the iobuffer set aside to hold buffered unwritten data.
 *
 * The only way to prevent that situation from occurring is to
 * put a cap on how much we read, and never read more data than
 * we can store in our write-buffer, encoded.
 * We can use gss_wrap_size_limit() in combination with the amount
 * of data free in the buffer to find out the max amount of data to
 * read, and read no more than that in the tcp case.
 *
 * The operation for writing thus becomes:
 * 1) Encode the data received and write it to the socket.
 *
 * 2) If we fail to write all the data, and it is a tcp socket,
 *    store the remaining data in the iobuffer, setting encodedlen
 *    to the size of data remaining, and used to zero.
 *    If it's a udp socket, there is not much to do, so return the
 *    error.
 *
 * 3) On subsequent write operations on the socket, try to write the
 *    data we had previously buffered.  Then continue with 1).
 *
 $ 4) When all data has been written, clear the iobuffer.
 *
 */

typedef enum { READ_BUF  = 0 /* MUST BE 0 or 1 */,
               WRITE_BUF = 1 /* MUST BE 0 or 1 */ } whichbuf_t;

typedef struct {
   unsigned char allocated;
   int           s;

#if HAVE_GSSAPI
#  if (SOCKD_BUFSIZE) < (2 * (MAXGSSAPITOKENLEN + GSSAPI_HLEN))
 #     error "SOCKD_BUFSIZE too small."
#  endif
#endif /* HAVE_GSSAPI */

   char         buf[2][SOCKD_BUFSIZE];

   struct {
      size_t   len;        /* length of decoded/plaintext data in buffer      */
      size_t   enclen;     /* length of encoded data in buffer.               */

      int      mode;       /* buffering mode.  Default is no buffering.       */
      ssize_t  size;       /*
                            * size of buffer to use.  Can not be larger than
                            * SOCKD_BUFSIZE.  Default is SOCKD_BUFSIZE.
                            */

#if SOCKS_CLIENT
      size_t   readalready;/*
                            * # of bytes we have already read from socket and
                            * should ignore.
                            */
#endif /* SOCKS_CLIENT */
   } info[2];

   int      stype;         /* socket type; tcp or udp                         */
} iobuffer_t;

typedef struct route_t {
   int              number;   /* route number.                                */

   struct {
      unsigned char autoadded;/* autoadded route?                             */
      size_t        failed;   /* route is bad?  How many times it has failed. */
      time_t        badtime;  /* if route is bad, time last marked as such.   */
   } state;

   socketoption_t   *socketoptionv;
   size_t           socketoptionc;

   ruleaddr_t       src;
   ruleaddr_t       dst;
   gateway_t        gw;

   ruleaddr_t       rdr_from;

   struct route_t   *next;      /* next route in list.               */
} route_t;

typedef struct {
   unsigned char        allocated;  /* allocated?                             */
   int                  control;    /* control connection to server.          */
   socksstate_t         state;      /* state of this connection.              */

   struct sockaddr_storage local;   /* local address of control connection.   */
                                    /* XXX does not look to be case for udp.  */

   struct sockaddr_storage server;  /* remote address of control connection.  */
   struct sockaddr_storage remote;  /* address server is using on our behalf. */
   struct sockaddr_storage reply;   /*
                                     * address to expect reply from, if not
                                     * same as control.
                                     */

   union {
      sockshost_t   accepted;   /* address server accepted for us.     */
      sockshost_t   connected;  /* address server connected to for us. */
   } forus;

   route_t      *route;
} socksfd_t;

/*
 * getaddrinfo(3) returns separate entries for udp and tcp, even when
 * everything else is the same.  That means we effectively only get half
 * MAX_ADDRINFO_NEXT unique ipaddresses at most.  We used 5 when we were
 * using the gethostby*(3) api, so double for getaddrinfo(3).
 * Might think about filtering out otherwise duplicate tcp/udp entries to
 * save memory.  Would make the cache less general though.
 *
 * An additional thing to consider is that there is no way to specify in
 * the getaddrinfo(3)-api that we want ipv4-mapped ipv6 addresses
 * returned too, when we set ai_family to AF_INET in hints.  The only way
 * to getr the ipv4-mapped addresses returned to is to set ai_family to
 * zero, but then we get the regular ipv6-addresses also.  Since there
 * are cases when we want the ipv4-mapped addresses returned also, we
 * need to make the size set here able to accomodate that too.
 */
#define MAX_ADDRINFO_NEXT (10)

typedef enum { id_name = 1, id_addr } hostent_id_t;

typedef struct {
   unsigned       allocated:1;      /* entry allocated?                       */
   time_t         written;          /* time this entry was created.           */

   /* if looked up address/name was found, 0.  Otherwise errorcode.  */
   int            gai_rc;

   /*
    * address or hostname used with DNS for this entry.
    * Note that gethostbyname(x) may return address k, but gethostbyaddr(k)
    * need not return the hostname 'x', so we need different entries for
    * hostnames and addresses and can not reuse one as the other.
    */
   hostent_id_t key;
   union {
      char                     name[MAXHOSTNAMELEN];
      struct sockaddr_storage  addr;
   } id;


   char            service[MAXSERVICELEN];

   union {
      struct {
            struct addrinfo addrinfo;
            /*
             * The pointers in addrinfo are set to point to the below memory,
             * to avoid having to do dynamic allocation/free repeatedly.
             */

            /*
             * there is only one hostname returned in struct addrinfo
             * by getnameinfo(3).
             */
            char            ai_canonname_mem[MAXHOSTNAMELEN];

            /* but there can be multiple addresses. */
            struct sockaddr_storage ai_addr_mem[MAX_ADDRINFO_NEXT];

            struct addrinfo         ai_next_mem[MAX_ADDRINFO_NEXT];

            struct addrinfo   *hints;
            struct addrinfo   hints_mem; /* memory for hints, if not NULL. */
      } getaddr;

      struct {
         char name[MAXHOSTNAMELEN];
         int  flags;
      } getname;
   } data;
} dnsinfo_t;


#define HOSTENT_MAX_ALIASES (5)
typedef struct {
   unsigned       allocated:1;      /* entry allocated?                       */
   unsigned       notfound:1;       /* looked up address/name was not found.  */
   time_t         written;          /* time this entry was created.           */


   /*
    * address or hostname used with DNS for this entry.
    * Note that gethostbyname(x) may return address k, but gethostbyaddr(k)
    * need not return the hostname 'x', so we need different entries for
    * hostnames and addresses and can not reuse one as the other.
    */
   hostent_id_t key;
   union {
      char            name[MAXHOSTNAMELEN];
      struct in_addr  ipv4;
   } id;

   struct hostent hostent;

   /*
    * The contents of hostent is set to point to the corresponding area here,
    * rather than allocating it on the stack.
    * We add one to HOSTENT_MAX_ALIASES because the last index is used
    * for NULL-terminating, as per the libresolv (rfc?) spec.
    */
   char h_name[MAXHOSTNAMELEN];
   char *h_aliases[HOSTENT_MAX_ALIASES + 1];
   char *h_addr_list[HOSTENT_MAX_ALIASES + 1];

   /* memory for above arrays. */
   char h_aliasesmem[HOSTENT_MAX_ALIASES + 1][MAXHOSTNAMELEN];
   char h_addr_listmem[HOSTENT_MAX_ALIASES + 1][MAX(sizeof(struct in_addr),
                                                    sizeof(struct in6_addr))];

} hostentry_t;

typedef struct {
#if !SOCKS_CLIENT
   interfaceside_t side;        /* what interface-side we are sending out on. */
   struct sockaddr_storage peer;/* peer we are receiving from.                */
#endif /* !SOCKS_CLIENT */

   int            type;       /* socket type; SOCK_DGRAM or SOCK_STREAM.      */
   int            flags;      /* flags set on the received data.              */

   size_t         fromsocket; /*
                               * number of bytes read from socket.  This
                               * may differ from the return value of the
                               * function if some sort of encapsulation
                               * is used (currently only gssapi is
                               * possible), or parts or all of the data was
                               * read from an internal buffer rather than
                               * from the socket itself.
                               * It may also be less than the return value,
                               * if more was read from the socket than was
                               * returned at this time.
                               */

   struct timeval ts;      /* time packet was received (for datagram only). */
} recvfrom_info_t;

typedef struct {
   interfaceside_t side; /*
                          * what interface-side we are sending out on.
                          * Only used by server.
                          */

   size_t          tosocket; /*
                              * number of bytes written to socket.  This
                              * may differ from the return value of the
                              * function if some sort of encapsulation
                              * (currently only gssapi is possible) is
                              * used, or parts or all of the data was
                              * written from an internal buffer rather
                              * than to the socket itself.
                              */
} sendto_info_t;




/*
 * versions of BSD's error functions that log via slog() instead.
 */

void serr(const char *fmt, ...)
          __ATTRIBUTE__((noreturn)) __ATTRIBUTE__((FORMAT(printf, 1, 2)));

void serrx(const char *fmt, ...)
          __ATTRIBUTE__((noreturn)) __ATTRIBUTE__((FORMAT(printf, 1, 2)));

void swarn(const char *fmt, ...)
           __ATTRIBUTE__((FORMAT(printf, 1, 2)));

void swarnx(const char *fmt, ...)
            __ATTRIBUTE__((FORMAT(printf, 1, 2)));


void
runenvcheck(void);
/*
 * Verify that run environment corresponds to build environment.
 */

long long
maxvalueoftype(const size_t typelen);
/*
 * Gives the maxvalue for a signed integer-type stored in a object of length
 * "typelen".
 */

long long
minvalueoftype(const size_t typelen);
/*
 * Gives the minvalue for a signed integer-type stored in a object of length
 * "typelen".
 */

unsigned long long
umaxvalueoftype(const size_t typelen);
/*
 * Gives the maxvalue for an unsigned integer-type stored in a object of length
 * "typelen".
 */

unsigned long long
uminvalueoftype(const size_t typelen);
/*
 * Gives the minvalue for an unsigned integer-type stored in a object of length
 * "typelen".
 */


void
genericinit(void);
/*
 * Generic init, called after clientinit()/serverinit().
 */

void
optioninit(void);
/*
 * sets options to a reasonable default.
 */

void
postconfigloadinit(void);
/*
 * To be called after config is loaded.
 */

int
socks_initupnp(gateway_t *gw, char *emsg, const size_t emsglen);
/*
 * Inits upnp for interface corresponding to the gateway "gw".
 * If successful, the necessary information to later use the found
 * upnp router is saved in "data", which should normally be part of a
 * route object.
 *
 * Returns:
 *    On success: 0.
 *    On failure: -1 (no appropriate upnp devices found, or some other error.)
 */

void
newprocinit(void);
/*
 * After a new process is started/forked, this function should
 * be called.  It will initialize various things, open needed
 * descriptors, etc. and can be called as many times as wanted.
 */

void *
udpheader_add(const sockshost_t *host, void *msg, size_t *len,
              const size_t msgsize);
/*
 * Prefixes the udpheader_t version of "host" to a copy of "msg",
 * which is of length "len".
 * "msgsize" gives the total size of the memory pointed to by "msg",
 * which may be up to "len" big.
 *
 * If "msgsize" is large enough the function will prepend the socks
 * udpheader to "msg", moving the old contents in "msg" to the right.
 * If not, NULL will be returned with errno set to EMSGSIZE.  This
 * should only happen if the payload + the socks udpheader is larger
 * than the maxsize of a UDP (IP) packet.
 *
 * Returns:
 *   On success: "msg" with the udpheader prepended.  The length of the new
       message is stored in "len".
 *   On failure: NULL (message to large).
 */

int
fdisopen(const int fd);
/*
 * returns true if the file descriptor "fd" currently references a open fd,
 * false otherwise.
 */

int
fdisblocking(const int fd);
/*
 * returns true if the file descriptor "fd" is blocking, false otherwise.
 */

void
closev(size_t ic, int *iv);
/*
 * Goes through "iv", which contains "ic" elements.
 * Each element that does not have a negative value is closed.
 */

const loglevel_t *
loglevel(const char *name);
/*
 * Returns the loglevel value having the name "name".
 * Returns NULL if there is no such loglevel.
 */


int
socks_logmatch(int d, const logtype_t *log);
/*
 * Returns true if "d" is a descriptor matching any descriptor in "log".
 * Returns false otherwise.
 */

struct sockaddr_storage *
int_sockshost2sockaddr2(const sockshost_t *shost, struct sockaddr_storage *addr,
                        size_t addrlen, int *gaierr,
                        char *emsg, size_t emsglen);
/*
 * Converts the sockshost_t "shost" to a sockaddr struct and stores it
 * in "addr".  If conversion fails, 0/0 is stored in "addr" and "gaierr"
 * is set to the resolver errorcode.  Otherwise, "gaierr" is set to 0.
 *
 * If "addr" is NULL, the function uses a static buffer which may be
 * overwritten on the next call to this function.
 *
 * If conversion fails, emsg contains the reason.  If failure is related
 * to DNS, "gaierr" is in addition set.
 *
 * Returns: "addr".
 *
 */

struct sockaddr_storage *
int_sockshost2sockaddr(const sockshost_t *shost, struct sockaddr_storage *addr,
                       size_t addrlen);
/*
 * like int_sockshost2sockaddr(), but without the "gaierr" argument.
 */


struct sockaddr_storage *
int_fakesockshost2sockaddr(const sockshost_t *host,
                           struct sockaddr_storage *addr, size_t addrlen);
/*
 * Like sockshost2sockaddr(), but checks whether the address in
 * "host" is fake when converting.
 */

struct sockaddr_storage *
int_urlstring2sockaddr(const char *string, struct sockaddr_storage *addr,
                       size_t addrlen, int *gaierr,
                       char *emsg, size_t emsglen);
/*
 * Converts the address given in "string", on URL:// format, to
 * a sockaddr address stored in "saddr".
 *
 * Returns "saddr" on success.
 *
 * Returns NULL on failure with the reason written to "emsg", which must
 * be of at least "emsglen" size.  If failure is due to resolver failure,
 * "gaierr" will contain the resolver errorcode, or 0 if not.
 */

sockshost_t *
sockaddr2sockshost(const struct sockaddr_storage *addr, sockshost_t *host);
/*
 * Converts the sockaddr struct "shost" to a sockshost_t struct and stores it
 * in "host".  If "host" is NULL, a static host object is used instead.
 *
 * Returns: a pointer to the object containing the sockshost_t representation.
 */

int
sockaddr2hostname(const struct sockaddr_storage *sa, char *hostname,
                  const size_t hostnamelen);
/*
 * reversemaps "sa" to hostname and stores it "hostname", which is at least
 * "hostnamelen" bytes big.
 *
 * Returns:
 *    0 on success.
 *    The corresponding getnameinf(3) error on failure.
 */

sockshost_t *
ruleaddr2sockshost(const ruleaddr_t *address, sockshost_t *host, int protocol);
/*
 * Converts the ruleaddr_t "address" to a sockshost_t struct and stores it
 * in "host".
 * Returns: "host".
 */

struct sockaddr_storage *
int_ruleaddr2sockaddr(const ruleaddr_t *address, struct sockaddr_storage *sa,
                      size_t salen, const int protocol);
/*
 * Converts the ruleaddr_t "address" to a sockshost_t struct and stores it
 * in "sa" if not NULL.
 *
 * Returns: "sa".
 */

struct sockaddr_storage *
int_ruleaddr2sockaddr2(const ruleaddr_t *address, struct sockaddr_storage *sa,
                       size_t salen, const int protocol, int *gaierr,
                       char *emsg, const size_t emsglen);
/*
 * Converts the ruleaddr_t "address" to a sockshost_t struct and stores it
 * in "sa" if not NULL.
 *
 * On error, "gaierr" may be set, and "emsg" will be set if not NULL.
 *
 * Returns: "sa".
 */



ruleaddr_t *
sockshost2ruleaddr(const sockshost_t *host, ruleaddr_t *addr);
/*
 * Converts the sockshost_t "host" to a ruleaddr_t struct and stores it
 * in "addr".
 * Returns: "addr".
 */

ruleaddr_t *
sockaddr2ruleaddr(const struct sockaddr_storage *addr, ruleaddr_t *ruleaddr);
/*
 * Converts the struct sockaddr "addr" to a ruleaddr_t struct and stores
 * it in "ruleaddr".
 * Returns: "addr".
 */

struct sockaddr_storage *
int_hostname2sockaddr(const char *name, size_t index,
                      struct sockaddr_storage *addr, size_t addrlen);
/*
 * Retrieves the address with index "index" for the hostname named "name".
 * Returns:
 *      On success: "addr", filled in with the address found.
 *      On failure: NULL (no address found).
 */

struct sockaddr_storage *
int_hostname2sockaddr2(const char *name, size_t index,
                       struct sockaddr_storage *addr, size_t addrlen,
                       int *gaierr, char *emsg, const size_t emsglen);
/*
 * Retrieves the address with index "index" for the hostname named "name".
 * Returns:
 *      On success: "addr", filled in with the address found.
 *      On failure: NULL (no address found).  "gaierr" contains the
 *                  resolver error, if available, and "emsg" contains
 *                  a textual description of the error.
 */


struct sockaddr_storage *
int_ifname2sockaddr(const char *ifname, size_t index,
                    struct sockaddr_storage *addr, size_t addrlen,
                    struct sockaddr_storage *mask, size_t masklen);
/*
 * Retrieves the address with index "index" on the interface named "ifname".
 * If "mask" is not NULL, the mask of the interface is stored here.
 *
 * Returns:
 *      On success: "addr", and possibly "netmask", filled in with the
 *                  address found.
 *      On failure: NULL (no address found on the interface at that index.
 */

const char *
sockaddr2ifname(struct sockaddr_storage *addr, char *ifname, size_t iflen);
/*
 * Retrieves the name of the interface the address "addr" belongs to.
 * The name is written to "ifname", which must be of len "iflen".
 * If "ifname" or "iflen" is NULL, the name is written to a local
 * buffer instead.
 *
 * Returns a pointer to the memory containing the interface name, or
 * NULL if no matching interface is found.
 *
 */

int
sockatmark(int s);
/*
 * If "s" is at oob mark, return 1, otherwise 0.
 * Returns -1 if a error occurred.
 */

ssize_t
recvmsgn(int s, struct msghdr *msg, int flags);
/*
 * Like recvmsg(), but handles some os-specific bugs.
 */

ssize_t
sendmsgn(int s, const struct msghdr *msg, int flags, const time_t timeoutms);
/*
 * Like sendmsg(), but retries on temporary errors, including blocking
 * with select(2) for up to "timeoutms" milliseconds.
 *
 * If "timeout" is -1, block forever, or until we've failed a predefined
 * number of maxtimes, whatever comes first.
 */

ssize_t
readn(int, void *, size_t, const size_t minread, authmethod_t *auth)
      __ATTRIBUTE__((__BOUNDED__(__buffer__, 2, 3)));
/*
 * Like read() but with two additional arguments:
 * minread - the minimum amount of bytes to read before returning, or error.
 * auth    - authentication info for the file descriptor.  May be NULL.
 */

ssize_t
writen(int, const void *, size_t, const size_t minwrite,
       authmethod_t *auth)
      __ATTRIBUTE__((__BOUNDED__(__buffer__, 2, 3)));
/*
 * like write() but if with two additional arguments:
 * minwrite - the minimum amount of bytes to write before returning, or error.
 * auth     - authentication info for the file descriptor.  May be NULL.
 */

ssize_t
socks_recvfrom(int s, void *buf, size_t len, int flags,
               struct sockaddr_storage *from,
               socklen_t *fromlen, recvfrom_info_t *recvflags,
               authmethod_t *auth)
               __ATTRIBUTE__((__BOUNDED__(__buffer__, 2, 3)));
/*
 * Similar to recvfrom(), but with two additional arguments:
 *  - auth:       if not NULL, the authentication used for this session.
 *  - recvflags:  if not NULL, information about the data received.
 */

ssize_t
socks_recvfromn(const int s, void *buf, size_t len, const size_t minread,
                const int flags, struct sockaddr_storage *from,
                socklen_t *fromlen, recvfrom_info_t *recvflags,
                authmethod_t *auth)
                __ATTRIBUTE__((__BOUNDED__(__buffer__, 2, 3)));
/*
 * Like socks_recvfrom(), but retries until minread has been read, or failure.
 */

ssize_t
socks_sendto(int s, const void *msg, size_t len, int flags,
             const struct sockaddr_storage *, socklen_t,
             sendto_info_t *sendflags, authmethod_t *auth)
             __ATTRIBUTE__((__BOUNDED__(__buffer__, 2, 3)));
/*
 * Like sendto(), but with two additional arguments:
 * - sendflags: if not NULL, updated with sendto_info upon return.
 */

ssize_t
socks_sendton(int s, const void *buf, size_t len, const size_t minwrite,
              int flags, const struct sockaddr_storage *to, socklen_t tolen,
              sendto_info_t *sendflags, authmethod_t *auth)
              __ATTRIBUTE__((__BOUNDED__(__buffer__, 2, 3)));
/*
 * Like socks_sendto(), but retries until "minwrite" is written, or failure.
 */

int
closen(int);
/*
 * Wrapper around close().  Retries on EINTR.
 */

struct timeval *
gettimeofday_monotonic(struct timeval *tv);
/*
 * Similar to gettimeofday(2), but time is monotonic.
 * Returns "tv", filled with the current time.
 */

time_t
time_monotonic(time_t *tloc);
/*
 * Similar to time(3), but time is monotonic.
 */

unsigned long
tv2us(const struct timeval *tv);
/*
 * converts "tv" to microseconds and returns the result.
 */

struct timeval *
us2tv(const unsigned long us, struct timeval *tv);
/*
 * converts "usec" to struct timeval and stores the result in "tv".
 * Returns "tv".
 */


int
selectn(int nfds, fd_set *rset, fd_set *bufrset, fd_set *buffwset,
         fd_set *wset, fd_set *xset, struct timeval *);
/*
 * Wrapper around select() that takes two additional arguments:
 * bufrset  - if not NULL, set to contain descriptors with data buffered
 *            for reading.
 * buffwset - if not NULL, set to contain descriptors with data buffered
 *            for writing (buffered-for-writing).
 *
 * In addition, if it's called by the server, it checks whether we
 * have a signal queued internally, and if so calls the appropriate
 * signal handler.
 */

int
acceptn(int, struct sockaddr_storage *, socklen_t *);
/*
 * Wrapper around accept().  Retries on EINTR.
 */

int
socks_socket(const int domain, const int type, const int protocol);
/*
 * Like socket(2), but also sets some options we always want to set.
 */


int
setblocking(const int fd, const char *context);
/*
 * Configures "fd" to use blocking i/o.
 * "context" provides the context "fd" will be used in.
 *
 * Returns:
 *    On success: the original fd-flags set on fd "fd" before the change.
 *    On failure: -1.  In this case errno will be set and a warning will
 *                     be logged using "context".
 */

int
setnonblocking(const int fd, const char *context);
/*
 * Configures "fd" to use non-blocking i/o.
 * "context" provides the context "fd" will be used in.
 *
 * Returns:
 *    On success: the original fd-flags set on fd "fd" before the change.
 *    On failure: -1.  In this case errno will be set and a warning will
 *                     be logged using "context".
 */

int
socks_socketisforlan(const int s);
/*
 * If we can determine that the socket "s" is for lan use only, i.e. should
 * not be proxied, returns true.  Otherwise, returns false.
 */

struct sockaddr_storage *
socketisconnected(const int s, struct sockaddr_storage *addr, socklen_t alen);
/*
 * If the socket "s" is connected to a peer, returns peer's address.
 * If "addr" is not NULL, the peer address is stored in "addr", and a
 * pointer to "addr" is returned.  Otherwise a static buffer is used
 * and a pointer to that static buffer is returned.
 *
 * If the socket "s" is not connected, NULL is returned.
 */

int
fdisdup(const int fd1, const int fd2);
/*
 * Tries to determine if file descriptor fd1 is a dup of fd2.
 * Returns true if yes, false if not.
 */


int
socks_rebind(int s, int protocol, struct sockaddr_storage *from,
             const struct ruleaddr_t *to, char *emsg, const size_t emsglen);
/*
 * Tries to rebind the socket 's", currently bound to address "from", if
 * any, to match the range given by "to".
 *
 * Returns 0 on success.
 * Returns 0 on failure.  Error will be written to emsg and errno will be set.
 */

int
socks_bindinrange(int s, struct sockaddr_storage *addr,
                  in_port_t first, in_port_t last, const enum operator_t op);
/*
 * Like sockd_bind(), but keeps trying to sockd_bind a address in the
 * range given by "addr", as indicated by "first", "last" and "op",
 * until whole range has been tried.
*/

int
socks_bind(int s, struct sockaddr_storage *addr, size_t retries);
/*
 * Binds the address "addr" to the socket "s".  The bind call will
 * be tried "retries" + 1 times if the error is EADDRINUSE, or until
 * successful, whatever comes first.
 *
 * If the port number is privileged, it will set and reset the euid
 * as appropriate.  (Only applies when called called by server.)
 *
 * If successful, "addr" is filled in with the bound address.
 * Returns:
 *      On success: 0.
 *      On failure:   -1
 */

const struct in_addr *
ipv4_addrisinlist(const struct in_addr *addr, const struct in_addr *mask,
                  const struct addrinfo *ailist);

const struct in6_addr *
ipv6_addrisinlist(const struct in6_addr *addr, const unsigned int maskbits,
                  const struct addrinfo *ailist);

/*
 * Compares "addr", bitwise AND-ed with "mask", against each IPv4 or IPv6
 * address * in "list", also bitwise AND-ed with "mask".
 *
 * Returns:
 *      If "list" contains a element matching "addr": pointer to the matching
                                                      address in ailist.
 *      otherwise: NULL.
 */


int
sockaddrareeq(const struct sockaddr_storage *a,
              const struct sockaddr_storage *b, const size_t nocompare);
/*
 * Compares the address "a" against "b".
 * If "nocompare" is not zero, the attributes set (ADDRINFO_PORT, etc.)
 * are excluded from the comparison.
 *
 * Returns:
 *      If "a" and "b" are equal: true
 *      else: false
 */


void
usrsockaddrcpy(struct sockaddr_storage *dst, const struct sockaddr_storage *src,
               const size_t len);
/*
 * Duplicate contents of sockaddr structure, up to len bytes.
 * Variant of sockaddrcpy() for sockaddr copying sockaddr data
 * from clients in Rfoo() functions.
 */

void
sockaddrcpy(struct sockaddr_storage *dst, const struct sockaddr_storage *src,
            const size_t len);
/*
 * Duplicate contents of sockaddr structure, up to len bytes.
 */

sa_len_type
salen(const sa_family_t family);
/*
 * returns the sockaddrlen of a sockaddr struct of family "family".
 */

sa_len_type
inaddrlen(const sa_family_t family);
/*
 * returns the ipaddresslen of an address of the familytype "family".
 */


int
safamily_issupported(const sa_family_t family);
/*
 * Returns true if we support the sockaddr family "family".
 * Returns false if we do not.
 */

sa_family_t
atype2safamily(const int atype);
/*
 * Returns the sa_family_t equivalent of the SOCKS address type
 * "atype", which must be one of SOCKS_ADDR_IPV4 or SOCKS_ADDR_IPV6.
 */

int
safamily2atype(const sa_family_t safamily);
/*
 * Returns the atype equivalent of the sa_family_t "safamily".
 */


int
addrinfo_issupported(const struct addrinfo *ai);
/*
 * Returns true if we support the addrinfo in "ai".
 * Returns false if we do not.
 */


/*
 * Wrapper around standard functions.
 */
const char *socks_strerror(const int err);
const char *socks_gai_strerror(const int err);

size_t
snprintfn(char *str, size_t size, const char *format, ...)
      __ATTRIBUTE__((FORMAT(printf, 3, 4)))
      __ATTRIBUTE__((__NONNULL__(3)))
      __ATTRIBUTE__((__BOUNDED__(__string__, 1, 2)));
/*
 * Wrapper around snprintf() for consistent behavior.  Same as stdio
 * snprintf() but the following are also enforced:
 *      returns 0 instead of -1 (rawterminates *str) on error.
 *      never returns a value greater than size - 1.
 */

void
socks_sigblock(const int sig, sigset_t *oldset);
/*
 * If "sig" is -1, blocks all signals.  If not, adds only "sig" to
 * the list of currently blocked signals.
 *
 * The old signal mask is returned in "oldset".
 */

void
socks_sigunblock(const sigset_t *oldset);
/*
 * Restores the current signal mask to "oldset".
 */


const char *
strcheck(const char *string);
/*
 * Checks "string".  If it is NULL, returns a string indicating memory
 * exhausted, if not, returns the same string it was passed.
 */

unsigned char *
sockshost2mem(const sockshost_t *host, unsigned char *mem, int version);
/*
 * Writes "host" out to "mem".  The caller must make sure "mem"
 * is big enough to hold the contents of "host".
 * "version" gives the socks version "host" is to be written out in.
 * Returns a pointer to one element past the last byte written to "mem".
 */

const unsigned char *
mem2sockshost(sockshost_t *host, const unsigned char *mem, size_t len,
      int version)
      __ATTRIBUTE__((__BOUNDED__(__buffer__, 2, 3)));
/*
 * Writes "mem", which is assumed to be a sockshost string
 * of length "len" in version "version" in network order, out to "host".
 * Returns:
 *      On success: pointer to one element past last byte used of mem
 *                  and fills in "host" appropriately.
 *      On failure: NULL ("mem" is not a valid sockshost.)
 */

unsigned int socks_get_responsevalue(const response_t *response);
void socks_set_responsevalue(response_t *response, unsigned int value);
/*
 * Functions to fetch or set the value of the response, depending on what
 * version the response belongs to.
 */

int *
charmethod2intmethod(const size_t methodc,
                     const unsigned char charmethodv[], int intmethodv[]);
/*
 * converts char method array "charmethodv" with "methodc" elements,
 * to a integer method array, storing the result in "intmethodv".
 *
 * Returns "intmethodv".
 */


int
proxyprotocolisknown(const int version);
/*
 * Returns true if "version" is a known proxy version.  0 if not.
 */

int
authmethodisknown(const int method);
/*
 * Returns true if "method" is a known authmethod.  0 if not.
 */

int
socks_addlogfile(logtype_t *logcf, const char *logfile);
/*
 * Adds the file "logfile" to the list of files we log to, stored in "logcf".
 *
 * Returns 0 on success.
 * Returns -1 on failure.
 */

void slog(int priority, const char *fmt, ...)
      __ATTRIBUTE__((FORMAT(printf, 2, 3)));
/*
 * Logs message "fmt" at priority "priority" to previously configured
 * output device.
 * Checks settings and ignores message if it's of to low a priority.
 */

void vslog(int priority, const char *fmt, va_list ap, va_list apcopy)
      __ATTRIBUTE__((FORMAT(printf, 2, 0)));
/*
 * Same as slog() but assumes varargs/stdargs have already processed
 * the arguments.
 */

void
signalslog(const int priority, const char *msgv[]);
/*
 * Similar to slog(), but simpler.
 *
 * "msgv" is an array of NUL-terminated strings.  The last element in this
 * array must be NULL.
 * The function logs all the strings in "msgv", as one.  Caller must take
 * care of any desired space between the strings.
 *
 * Can be called from a signalhandler.
 */



int
parseconfig(const char *filename);
/*
 * Parses the config stored in in the filename "filename", as well
 * as environment-variables related.
 *
 * Returns:
 *      On success: 0.
 *      On failure: -1.
 */

void
resetconfig(struct config *config, const int exiting);
/*
 * resets the config "config" back to default, freeing memory as well.
 * If "exiting" is true, we are exiting and don't need to save
 * anything.
 */


int
addrmatch(const ruleaddr_t *rule, const sockshost_t *address,
          sockshost_t *addrmatched, int protocol, int ipalias);
/*
 * Tries to match "address" against "rule".  "address" is resolved
 * if necessary.  "rule" supports the wildcard INADDR_ANY and port of 0.
 * "protocol" is the protocol to compare under.
 *
 * If "ipalias" is true and "address" is an IP-address, the function will
 * try to reverse-map "address" to hostname, the hostname to ip, and match
 * those ipaddresses against "rule".
 *
 * Returns true if "rule" matched "address".  In this case, if "addrmatched"
 * is not NULL, it is updated to reflect the address that matched, which may
 * be different from "address" if "address" had to be resolved or
 * reversemapped.
 */

int
socks_connecthost(int s,
#if !SOCKS_CLIENT
                  const interfaceside_t side,
#endif /* !SOCKS_CLIENT */
                  const sockshost_t *host,
                  struct sockaddr_storage *laddr,
                  struct sockaddr_storage *raddr,
                  const long timeout, char *emsg, const size_t emsglen);
/*
 * Tries to connect to "host".  If "host"'s address is not a IP address,
 * the function also tries to connect to any alias for "host"'s
 * name.  The connection is done using the open descriptor "s".
 *
 * If "laddr" is not NULL, it is filled in with the address we connected to
 * "host" from, if a connect(2) was initiated.
 *
 * If "raddr" is not NULL, it is filled in with the address connected to if
 * successful.  If "host" is a an ip address, it will be identical to that
 * ip address, but if "host" is a hostname, they will of course differ.
 *
 * If "timeout" is not negative, it gives the timeout for how long to wait
 * for the connect to complete.  A value of zero means no wait will be
 * done, and the the function may return with errno set to EINPROGRESS.
 * A negative value for timeout means wait the kernel/system default.
 *
 * If the function fails, the reason is written to emsg, which must be
 * at least "emsglen" long.
 *
 * Returns:
 *      On success: 0
 *      On failure: -1.  Reason for error is written to emsg.
 */

route_t *
socks_connectroute(const int s, socks_t *packet,
                   const sockshost_t *src, const sockshost_t *dst,
                   char *emsg, const size_t emsglen);
/*
 * Finds a route from "src" to "dst" and connects to it "s".
 * If src or dst is NULL, that argument is ignored.
 *
 * The route used may take into account the contents of "packet->req",
 * which is assumed to be the packet that will be sent to a socks server,
 * so it is recommended that it's contents be as conservative as possible.
 *
 * When it has successfully connected to a gateway it will set
 * the packet->method members to point to the methods the gateway
 * should be offered.
 *
 * Returns:
 *      On success: the route that was used.
 *      On failure: NULL.  See emsg for reason.
 */

route_t *
socks_requestpolish(request_t *req, const sockshost_t *src,
                    const sockshost_t *dst);
/*
 * Tries to "polish" (modify) the request "req" for a session from "src"
 * to "dst", so that a later socks_getroute() will succeed.
 *
 * Returns:
 *      On success: the route that will match the polished request.
 *      On failure: NULL.
 */

int
socks_routesetup(const int control, const int data, const route_t *route,
                 char *emsg, const size_t emsglen);
/*
 * Prepares for establishing a session via route "route".
 * "control" gives the controlsocket that will be used.
 * "data" gives the data socket that will be used.
 *
 * Return 0 on success.
 * Returns -1 on failure.  Reason for failure will be stored in "emsg", and
 *                         errno will be set appropriately.
 */

void
showstate(const serverstate_t *state);
/*
 * logs a printable representation of "state" to the logfile.
 */

void
showmethod(objecttype_t type, size_t methodc, const int *methodv);
/*
 * Shows methods set in "methodv" array.
 * "type" indicates whether the methods are for a client/hostid-rule,
 * and thus are clientmethods, or for a socksrule, and thus are socksmethods.
 */

void
showtimeout(const timeout_t *timeout);
/*
 * shows timeouts set in "timeout".
 */


void
freeroutelist(route_t *routehead);
/*
 * Frees a list of routes and their contents, starting at "routehead".
 */

route_t *
socks_addroute(const route_t *route, const int last);
/*
 * Appends a copy of "route" to our list of routes.
 * If "last" is true, the route is added to the end of our list.
 * If not, it's added to the start, and existing rule numbers are updated
 * correspondingly.
 *
 * Returns a pointer to the added route.
 */

route_t *
socks_autoadd_directroute(const command_t *commands,
                          const protocol_t *protocols,
                          const struct sockaddr_storage *saddr,
                          const struct sockaddr_storage *netmask);
/*
 * Adds a direct route to "saddr", netmask "netmask", for the commands
 * "commands" and protocols "protocols".
 *
 * Intended to be used for routes that are added automatically,
 * and not via socks.conf.
 */

void
socks_showroute(const route_t *route);
/*
 * prints the route "route".
 */

route_t *
socks_getroute(const request_t *req, const sockshost_t *src,
               const sockshost_t *dst);
/*
 * Tries to find a  route to be used for a connection going from
 * "src" to "dst".
 * If src or dst is NULL, that argument is ignored.
 *
 * The route used may take into account the contents of "req", which is
 * assumed to be the packet that will be sent to a socks server, so it is
 * recommended that it's contents be as conservative as possible.
 *
 * Returns:
 *      On success: pointer to route that should be used.
 *      On failure: NULL (no route found).
 */

unsigned int
sockscode(const int version, const int code);
/*
 * Maps the socks reply code "code", which is in non-version specific format,
 * to the equivalent reply code in version "version".
 */

unsigned int
errno2reply(int errnum, int version);
/*
 * Returns the proxy version "version" reply code for a error of type "errno".
 */

char *
str2vis(const char *string, size_t len, char *visstring, size_t vislen)
      __ATTRIBUTE__((__BOUNDED__(__string__, 3, 4)));
/*
 * Visually encodes exactly "len" chars of "string" and stores the
 * result in "visstring", which is of length "vislen".  "vislen" should
 * be at least "len" * 4 + 1.
 * Note that the function really will encode len characters, including
 * any NUL-characters.
 *
 * Returns: the visually encoded string, "visstring".
 */

in_addr_t
socks_addfakeip(const char *name);
/*
 * Adds "name" to a internal table indexed by (fake)IP addresses.
 * Returns:
 *      On success: "name"'s index.
 *      On failure:   INADDR_NONE
 */

const char *
socks_getfakehost(in_addr_t addr);
/*
 * If "addr" is a "fake" (non-resolved) addr, it returns the name
 * corresponding to it.
 * Else, NULL is returned.
 */

int
socks_getfakeip(const char *host, struct in_addr *addr);
/*
 * If "host" has a fake address entry, the address is written into
 * "addr".
 * Returns:
 *      If a fake address exits: true
 *      Else: false
 */

sockshost_t *
fakesockaddr2sockshost(const struct sockaddr_storage *addr, sockshost_t *host);
/*
 * Identical to sockaddr2sockshost, but checks whether
 * the address in "addr" is a "fake" one when converting.
 */

int
sockshostareeq(const sockshost_t *a, const sockshost_t *b);
/*
 * Compares the address "a" against "b".
 * Returns:
 *      If "a" and "b" are equal: true
 *      else: false
 */

int
fdsetop(int highestfd, int op, const fd_set *a, const fd_set *b,
        fd_set *result);
/*
 * Performs operation on descriptor sets.
 * "highestfd" is the descriptors with the highest index to perform operation
 * "op" on in the sets "a" and "b".
 *
 * The result of the operation is stored in "result".
 *
 * Returns the number of the highest descriptor set in "result".
 * NOTES:
 *      - operators supported is: AND ('&'), XOR ('^'), and OR ('|').
 */

int
methodisset(int method, const int *methodv, size_t methodc);
/*
 * Returns true if the method "method" is set in "methodv", false otherwise.
 * "methodc" is the length of "methodv".
 */


char *
get_tcpinfo(const size_t fdc, int fdv[], char *buf, size_t buflen);
/*
 * Retrieves tcp_info for the sockets in "fdv" and stores it in "buf", if
 * buf is not NULL.
 * If buf or buflen is not set, stores it in locally allocated memory
 * and return a pointer to it rather than to buf.
 *
 * If tcpinfo can not be retrieved for any of the sockets in fdv,
 * that index in fdv is set to -1.
 *
 * Returns:
 *    String with tcpinfo values, or NULL if no tcpinfo could be retrieved.
 */

int
socketoptdup(int s, int new_s);
/*
 * Duplicates the settings of "s" onto "new_s".  If "new_s" is -1,
 * a new socket is created for it.
 *
 * Returns:
 *      On success: new_s (or the descriptor for the new socket if new_s is -1).
 *      On failure: -1
 */

void
socketoptioncheck(const socketoption_t *option);
/*
 * Check socketoption arguments against sockopt_t entry.
 */

int
addedsocketoption(size_t *optc, socketoption_t **optv,
                  const socketoption_t *newoption);
/*
 * Adds the socketoption "newoption" to the list of current options
 * in the socketoption array "optv".
 *
 * Returns true on success. false on failure.
 */

void setconfsockoptions(const int target, const int in, const int protocol,
                        const int isclientside,
                        const size_t optc, const socketoption_t *optv,
                        const int whichlocals, const int whichglobals);
/*
 * Sets the options in "optv" on the socket "target", presumably loaded from
 * the sockd.conf.  "target" should be a socket of the type indicated by
 * protocol (SOCKS_TCP or SOCKS_UDP).
 *
 * If "in" is not -1, it indicates the socket the socket a connection from
 * a client came in from, and perhaps the reason "target" was created.
 * This is used in some special cases where we need to copy some special
 * options from the client connection (e.g., hostids).
 *
 * "isclientside" indicates whether "s" is a socket for the internal (client)
 * or external interface.
 *
 * "whichglobals" indicates what global (not rule/route-specific) options
 * configured should be checked at this time, and "whichlocals" the
 * same for the options in optv.
 */

int
socks_mklock(const char *template, char *newname, const size_t newnamelen);
/*
 * Creates a file that can be used with socks_lock() and
 * socks_unlock().  Returns the file descriptor of the created file.
 * If "newname" or "newnamelen" is zero, the created file is unlinked.
 * Otherwise the file is not unlinked and the name of the created file is
 * is saved to newname.
 *
 * Returns:
 *      On success: file descriptor
 *      On failure: -1
 */

int
socks_lock(const int fd, const off_t offset, const off_t len,
           const int exclusive, const int wait);
/*
 * Looks the file descriptor "fd" at offset "offset", length "len".
 * If "exclusive" is true, the lock is exclusive.  If not, it is shared.
 * If "wait" is true, wait for the lock.  If not, return if the lock
 * can not be taken.
 *
 * Upgrade/downgrade to/from exclusive is permitted.
 *
 * Returns:
 *      On success: 0
 *      On error  : -1
 */

void
socks_unlock(int d, const off_t offset, const off_t len);
/*
 * Unlocks the file descriptor "d", previously locked by this process,
 * at offset "offset", length "len".
 */

int
bitcount(unsigned long number);
/*
 * Returns the number of bits set in "number".
 */

int
bitcount_in6addr(const struct in6_addr *in6addr);
/*
 * Returns the number of bits set in "in6addr".
 */


#if SOCKSLIBRARY_DYNAMIC
/*
 * Here because they may be indirectly used by the server too, when it
 * executes external library code (e.g., libwrap).
 */

struct hostent *sys_gethostbyaddr(const char *addr, socklen_t len, int af);
struct hostent *sys_gethostbyname(const char *);
struct hostent *sys_gethostbyname2(const char *, int);

#if HAVE_GETADDRINFO
int sys_getaddrinfo(const char *nodename, const char *servname,
                    const struct addrinfo *hints, struct addrinfo **res);
#endif /* HAVE_GETADDRINFO */

#if HAVE_GETIPNODEBYNAME
struct hostent *sys_getipnodebyname(const char *name, int af, int flags,
                                    int *error_num);
#endif /* HAVE_GETIPNODEBYNAME */

#if SOCKS_CLIENT
#if HAVE___FPRINTF_CHK
HAVE_PROT_FPRINTF_0 __fprintf_chk(HAVE_PROT_FPRINTF_1 stream, int dummy,
              HAVE_PROT_FPRINTF_2 format, ...);
#endif /* HAVE___FPRINTF_CHK */

#if HAVE___VFPRINTF_CHK
HAVE_PROT_VFPRINTF_0 __vfprintf_chk(HAVE_PROT_VFPRINTF_1 stream,
      int dummy, HAVE_PROT_VFPRINTF_2 format, HAVE_PROT_VFPRINTF_3 ap);
#endif /* HAVE___VFPRINTF_CHK */
#endif /* SOCKS_CLIENT */

#if HAVE___READ_CHK
HAVE_PROT__READ_CHK_0
__read_chk(HAVE_PROT__READ_CHK_1 d, HAVE_PROT__READ_CHK_2 buf,
           HAVE_PROT__READ_CHK_3 nbytes, HAVE_PROT__READ_CHK_4 buflen);
#endif /* HAVE___READ_CHK */

#endif /* SOCKSLIBRARY_DYNAMIC */

int
httpproxy_negotiate(int control, socks_t *packet,
                    char *emsg, const size_t emsglen);
/*
 * Negotiates a session to be used with the server connected to "control".
 * "packet" is the packet with information about what we want the
 * server to do for us.
 * packet->res.reply will be set according to the result of negotiation.
 * Returns:
 *      On success: 0 (server accepted our request).
 *      On failure: -1.  "emsg" will contain the details.
 */

int
upnp_negotiate(const int s, socks_t *packet, gateway_t *gw,
               char *emsg, const size_t emsglen);
/*
 * Negotiates a session to be used with the upnp server.
 * If the request is for a i/o operation, socket is the socket to be used
 * for performing the i/o.
 *
 * "packet" is the packet with information about what we want the
 * server to do for us.
 *
 * "gw" is the upnp gateway to used.
 *
 * packet->res.reply will be set according to the result of negotiation.
 *
 * Returns:
 *      On success: 0 (server accepted our request).
 *                  Note that we do not need to contact the UPNP router
 *                  for all requests.  If we do not need to contact it for
 *                  the given request, we will just pretend everything is ok.
 *
 *      On failure: -1.  "emsg" will contain the details.
 */

int
socks_negotiate(int s, int control, socks_t *packet, route_t *route,
                char *emsg, const size_t emsglen);
/*
 * "s" is the socket data will flow over.
 * "control" is the control connection to the socks server.
 * "packet" is a socks packet containing the request.
 *   "route" is the connected route.
 * Negotiates method and fills the response to the request into packet->res.
 *
 * Returns:
 *      On success: 0 (server replied to our request).
 *      On failure: -1.  Reason is stored in "emsg" and errno is set.
 */

int
serverreplyisok(const unsigned int version, const unsigned int command,
                const unsigned int reply, route_t *route,
                char *emsg, const size_t emsglen);
/*
 * "replycode" is the reply code returned by a socks server of version
 * "version".
 * "route" is the route that was used for the socks server.
 * If the error code indicates a server failure, the route might be
 * "blacklisted".
 *
 *  On success: true.
 *  On failure: false.  Reason is stored in "emsg" and errno is set.
 */

route_t *
socks_nbconnectroute(int s, int control, socks_t *packet,
                     const sockshost_t *src, const sockshost_t *dst,
                     char *emsg, const size_t emsglen);
/*
 * The non-blocking version of socks_connectroute(), only used by client.
 * Takes one additional argument, "s", which is the socket to connect
 * and not necessarily the same as "control" (msproxy case).
 */

void
socks_blacklist(route_t *route, const char *reason);
/*
 * Marks route "route" as bad.
 * "reason" is a short reason describing why we are blacklisting this route.
 */

void
socks_clearblacklist(route_t *route);
/*
 * Clears bad marks on route.
 */

int
methodisvalid(const int method, objecttype_t ruletype);
/*
 * Returns true if "method" is a valid method for rules of type
 * "ruletype".
 */

int
negotiate_method(int s, socks_t *packet, route_t *route,
                 char *emsg, const size_t emsglen);
/*
 * Negotiates a method to be used when talking with the server connected
 * to "s".
 * "packet" is the packet that will later be sent to server, and only
 * the "auth" element in it will be set but other elements are needed
 * for reading too.
 * "route" is the route selected for connecting to the socks-server.
 *
 * Returns:
 *      On success: 0
 *      On failure: -1.  "emsg" will contain the details.
 */

int
clientmethod_uname(int s, const sockshost_t *host, int version,
                   unsigned char *name, unsigned char *password,
                   char *emsg, size_t emsglen);
/*
 * Enters username/password negotiation with the socks server connected to
 * the socket "s".
 * "host" gives the name of the server.
 * "version" gives the socks version established to use.
 * "name", if not NULL, gives the name to use for authenticating.
 * "password", if not NULL, gives the name to use for authenticating.
 * Returns:
 *      On success: 0
 *      On failure: -1.  "emsg" will contain the details.
 */

#if HAVE_GSSAPI
int
clientmethod_gssapi(int s, int protocol, const gateway_t *gw,
                    int version, authmethod_t *auth,
                    char *emsg, const size_t emsglen);
/*
 * Enters gssapi negotiation with the socks server connected to
 * the socket "s".
 * "gw" gives the name of the gateway.
 * "version" gives the socks version established to use.
 * "*auth", authentication structure
 * Returns:
 *      On success: 0
 *      On failure: -1.  "emsg" will contain the details.
 */

int
gssapi_encode(const gss_buffer_t in, gssapi_state_t *gs, gss_buffer_t out);
/*
 * gssapi encodes the data in "in", storing the encoded message
 * in "out", which contains a pointer to the previously allocated
 * memory of the specified length.
 *
 * "gs" contains details about gssapi context.
 *
 * Returns:
 *    On success: 0
 *    On failure: -1
 */

int
gssapi_decode(const gss_buffer_t in, gssapi_state_t *gs, gss_buffer_t out);
/*
 * gssapi decodes the data in "in", storing the decoded message
 * in "out", which contains a pointer to the previously allocated
 * memory of the specified length.
 *
 * "gs" contains details about gssapi context.
 *
 * Returns:
 *    On success: 0
 *    On failure: -1
 */

#endif /* HAVE_GSSAPI */


int socks_yyparse(void);
int socks_yylex(void);

int
socks_sendrequest(int s, const request_t *request,
                  char *emsg, const size_t emsglen);
/*
 * Sends the request "request" to the socks server connected to "s".
 * Returns:
 *      On success: 0
 *      On failure: -1.  Reason is stored in "emsg" and errno is set.
 */

int
socks_recvresponse(int s, response_t *response, int version,
                   char *emsg, const size_t emsglen);
/*
 * Receives a socks response from the "s".  "response" is filled in with
 * the data received.
 * "version" is the protocol version negotiated.
 *
 * Returns:
 *      On success: 0
 *      On failure: -1.  Reason is stored in "emsg" and errno is set.
 */

iobuffer_t *
socks_allocbuffer(const int s, const int type);
/*
 * Returns the iobuffer allocated to file descriptor "s", or
 * a new free one if none is allocated.
 * "type" gives the type of socket "s" is, SOCK_STREAM or SOCK_DGRAM.
 *
 * It is an error if a new buffer is allocated to "s" before the old
 * one has been freed.
 */

void
socks_initbuffer(const int fd, const int stype, iobuffer_t *iobuf);

iobuffer_t *
socks_getbuffer(const int s);
/*
 * Returns the iobuffer allocated to file descriptor "s".
 */

void
socks_freebuffer(const int s);
/*
 * Marks the iobuffer allocated to file descriptor "s" as free.
 * It is not an error if no iobuffer is currently allocate dto "s".
 */

void
socks_reallocbuffer(const int old, const int new);
/*
 * Reallocs the buffer assigned to "old", if any, to instead be assigned
 * to "new".
 */

void
socks_clearbuffer(const int s, const whichbuf_t type);
/*
 * Clears the iobuffer belonging to "s".
 * "type" gives the buffer-type that should be cleared, READ_BUF or WRITE_BUF.
 */

int socks_flushbuffer(const int s, const ssize_t len,
                      sendto_info_t *sendtoflags);
/*
 * Tries to flush the data buffered for file descriptor "s".  If "s" is -1,
 * data for all descriptors is flushed.
 *
 * If "len" is -1, tries to flush all data on that fd, otherwise only flushes
 * up to "len" bytes.
 *
 * If "sendtoflags" is not NULL, it is updated appropriately.
 *
 * Returns 0 if all data, if any was flushed.
 * Returns -1 otherwise.
 */

void
socks_setbuffer(iobuffer_t *iobuf, const int mode, ssize_t bufsize);

void
socks_setbufferfd(const int fd, const int mode, ssize_t bufsize);

/*
 * The above two functions perform the same operation, but one takes
 * a fd as the id to identify the iobuf and results in a no-op if no iobuf
 * is allocated to the fd, while the other takes the iobuf directly.
 *
 * Sets a flag in the iobuf belonging to "fd", indicating data should
 * not be be written before a flush is done, the buffer becomes full,
 * or "another good reason" is given, according to "mode".
 * "mode" can take the same values as the corresponding argument
 * to setvbuf(3).
 *
 * "bufsize" is the size of buffer to use.  "bufsize" for the read buffer
 * and "bufsize" for the writebuffer.  Can not be larger than SOCKD_BUFSIZE.
 * Use -1 for a default value (SOCKD_BUFSIZE).
 */

size_t socks_addtobuffer(const int s, const whichbuf_t which,
                         const int encoded, const void *data,
                         const size_t datalen)
       __ATTRIBUTE__((__BOUNDED__(__buffer__, 4, 5)));
/*
 * Adds "data", of length "datalen" to the buffer belonging to "s".
 * "which" must have one of the values WRITE_BUF or READ_BUF, to
 * indicate what part of the buffer to add the data to;
 * READ_BUF : data that has been read from the socket.
 * WRITE_BUF: data that should be written to the socket.
 *
 * Returns the number of bytes added.
 */

size_t
socks_getfrombuffer(const int s, const size_t flags, const whichbuf_t which,
                    const int encoded, void *data, size_t datalen)
                    __ATTRIBUTE__((__BOUNDED__(__buffer__, 5, 6)));

/*
 * Copies up to "datalen" bytes from the iobuf belonging to "s".
 *
 * Flags can be either 0 or MSG_PEEK.  If MSG_PEEK, the data read
 * from the buffer will not be removed.
 *
 * "which" must have one of the values WRITE_BUF or READ_BUF, to
 * indicate what part of the buffer to copy the data from.
 *
 * Returns the number of bytes copied.
 */

size_t
socks_bytesinbuffer(const int s, const whichbuf_t which, const int encoded);
/*
 * Returns the number of bytes currently in the iobuf belonging to "s".
 */

int
socks_bufferhasbytes(const int s, const whichbuf_t which);
/*
 * Returns true if any of the buffers (encoded or decoded) belonging
 * to "s" has data in it.
 * Intended to be faster than calling socks_bytesinbuffer() twice,
 * once for each buffer (encoded/decoded).
 */

size_t
socks_freeinbuffer(const int s, const whichbuf_t which);
/*
 * Returns the number of bytes free in the iobuf belonging to "s".
 */

size_t
socks_buffersize(const int s, const whichbuf_t which);
/*
 * Returns the total size of the buffer belonging to "s".
 */


#if HAVE_LIVEDEBUG

void
socks_flushrb(void);
/*
 * Flushes the ringbuffer to log(s).
 */

#endif /* HAVE_LIVEDEBUG */


fd_set *
allocate_maxsize_fdset(void);
/*
 * Allocate a fd_set big enough to hold the highest file descriptor
 * we could possibly use.
 * Returns a pointer to the allocated fd_set, or exits on failure.
 */

rlim_t
getmaxofiles(limittype_t type);
/*
 * Return max number of open files for process.
 * If type is softlimit, the current limit is returned.
 * If type is hardlimit, the absolute maximum value is returned.
 */

char *
socks_getusername(const sockshost_t *host, char *buf, size_t buflen)
      __ATTRIBUTE__((__BOUNDED__(__string__, 2, 3)));
/*
 * Tries to determine the username of the current user, to be used
 * when negotiating with the server "host".
 * The NUL-terminated username is written to "buf", which is of size
 * "buflen".
 * Returns:
 *      On success: pointer to "buf" with the username.
 *      On failure: NULL.
 */

char *
socks_getpassword(const sockshost_t *host, const char *user,
      char *buf, size_t buflen);
/*
 * Tries to determine the password of user "user", to be used
 * when negotiating with the server "host".
 * The NUL-terminated password is written to "buf", which is of length
 * "buflen"
 * Returns:
 *      On success: pointer to "buf" with the password.
 *      On failure: NULL.
 */

char *
socks_getenv(const char *name, value_t value);
/*
 * Depending on how the program was ./configured and on what
 * platform it runs, getenv(3) may or may not be disabled for
 * some names, for security reasons.
 *
 * This wrapper will return NULL if getenv(3) is disabled,
 * otherwise it will return the result of getenv(3).
 *
 * In addition, if "value" is not "dontcare", the function will
 * also compare the value returned by getenv(3), if any, to
 * see it it matches the value described by "value".  If they don't
 * match, the function will return NULL.
 */

int
socks_msghaserrors(const char *prefix, const struct msghdr *msg);
/*
 * Checks if "msg", as received via recvmsg(2), was truncated or
 * had other detectable errors, and reports it if so.
 * If reporting, "prefix" should contain information about where
 * the message was received.
 *
 * Returns true if "msg" has errors, "false" if not.
 */

void seconds2days(unsigned long *seconds, unsigned long *days,
                  unsigned long *hours, unsigned long *minutes);
/*
 * Converts "seconds" to the corresponding number of days, hours, minutes,
 * and seconds.
 * Upon return, the days, hours, minutes, and seconds are stored in the
 * passed arguments.
 */

void
showconfig(const struct config *config);
/*
 * prints out config "config".
 */

void
sockopts_dump(void);
/*
 * list all known socket option information
 */

const sockopt_t *
optname2sockopt(char *optname);
/*
 * return pointer to the socket option with the given name or NULL on failure.
 */

const sockopt_t *
optval2sockopt(int level, int optval);
/*
 * return pointer to the socket option with the the name "optname"
 * at the socket level "level", or NULL if no such option is known at
 * the given socket level.
 */

const sockopt_t *
optid2sockopt(size_t optid);
/*
 * return a pointer to the sockopt_t entry identified by "optid".
 */

const sockoptvalsym_t *
optval2valsym(size_t optid, char *name);
/*
 * returns a pointer to the sockoptvalsym entry if "name" is a valid symbolic
 * name for the socketoption indicated by "optid", or NULL if no matching
 * entry is found.
 */

#if HAVE_SOCKS_HOSTID
unsigned char
getsockethostid(const int s, const size_t addrc, struct in_addr addrv[]);
/*
 * Gets the hostids set on socket "s" and stores them in "addrv", which must
 * be big enough to hold at least "addrc" elements.
 *
 * Returns the number of hostids set on socket "s".
 * If none are set, 0 is returned.
 */

int
setsockethostid(const int s, const size_t addrc, struct in_addr addrv[]);
/*
 * Sets the hostids in "addrv", which contains "addrc" hostids, on socket
 * "s".
 *
 * Returns 0 on success, -1 on failure.
 */
#endif /* HAVE_SOCKS_HOSTID */


#if COVENANT
char *socks_decode_base64(char *in, char *out, size_t outlen);
char *socks_strcasestr(const char *a, const char *b);
#endif /* COVENANT */

#if HAVE_GETNAMEINFO && HAVE_PRELOAD

HAVE_PROT_GETNAMEINFO_0
sys_getnameinfo(HAVE_PROT_GETNAMEINFO_1 sa, HAVE_PROT_GETNAMEINFO_2 salen,
                HAVE_PROT_GETNAMEINFO_3 host, HAVE_PROT_GETNAMEINFO_4 hostlen,
                HAVE_PROT_GETNAMEINFO_5 serv, HAVE_PROT_GETNAMEINFO_6 servlen,
                HAVE_PROT_GETNAMEINFO_7 flags);

#endif /* HAVE_GETNAMEINFO && HAVE_PRELOAD */

#if SOCKS_CLIENT

#include "socks.h"

#else /* SOCKS_SERVER */

#include "sockd.h"

#endif /* SOCKS_SERVER */

#include "interposition.h"
#include "tostring.h"
#include "fmt.h"

#if HAVE_GSSAPI
#include "socks_gssapi.h"
#endif /* HAVE_GSSAPI */

void
slogstack(void);
/*
 * Prints the current stack.
 */

int
socks_getifaddrs(struct ifaddrs **ifap);
/*
 * Wrapper around getifaddrs(3) that does some extra work that should
 * not cause any problems.
 */


int
socks_inet_pton(const int af, const void *src, void *dst, uint32_t *dstscope);
/*
 * Like inet_pton(3), but calls getaddrinfo(3) to get the address instead
 * if "src" contains something that looks like a scope id (%id).  If so,
 * the scopeid is stored in "dstscope", provided "dstscope" is not NULL.
 *
 * Returns the same values as inet_pton().
 */

void
set_hints_ai_family(int *ai_family);
/*
 * Sets the "ai_family" member of a strut addrinfo "hints" object
 * appropriately for our use, according to whether we have usable
 * IPv6 addresses configured or not.
 */

int
makedummyfd(const sa_family_t safamily, const int socktype);
/*
 * Creates a dummy socket of the appropriate type, or the easiest/fastest
 * type if both safamily and socktype are zero.
 */


/*
 * Makes a dummy filedescriptor and returns it's index, or -1 on failure.
 */

#if DEBUG

void
printsocketopts(const int s);
/*
 * prints socket options and other flags set on the socket "s".
 */

int
fd_isset(int fd, fd_set *fdset);
/* function version of FD_ISSET() */

#endif /* DEBUG */

#endif /* !_COMMON_H_ */
