#include <pwd.h>
#include <grp.h>
+#ifdef HAVE_LIBADNS
+# define ADNS_FEATURE_MANYAF
+# include <adns.h>
+#endif
+
#include <mLib/alloc.h>
#include <mLib/arena.h>
#include <mLib/base64.h>
-#include <mLib/bres.h>
+#ifndef HAVE_LIBADNS
+# include <mLib/bres.h>
+#endif
#include <mLib/codec.h>
#include <mLib/daemonize.h>
#include <mLib/dstr.h>
/*----- Data structures ---------------------------------------------------*/
+/* --- The address-family table --- */
+
+#define ADDRFAM(_) \
+ _(INET, want_ipv4) \
+ _(INET6, want_ipv6)
+
+enum {
+#define ENUM(af, qf) AFIX_##af,
+ ADDRFAM(ENUM)
+#undef ENUM
+ NADDRFAM
+};
+
+extern const struct addrfam {
+ int af;
+ const char *name;
+#ifdef HAVE_LIBADNS
+ adns_queryflags qf;
+#endif
+} aftab[NADDRFAM];
+
/* --- Socket addresses --- *
*
* A magic union of supported socket addresses.
typedef union addr {
struct sockaddr sa;
struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
} addr;
/* --- Mapping keyed on addresses --- */
struct tunnel { const tunnel_ops *ops; };
#endif
+typedef struct tun_iter {
+ const struct tunnel_node *next;
+} tun_iter;
+
/* --- Peer statistics --- *
*
* Contains various interesting and not-so-interesting statistics about a
char *name; /* Peer's name */
char *privtag; /* Private key tag */
char *tag; /* Public key tag */
+ char *knock; /* Knock string, or null */
const tunnel_ops *tops; /* Tunnel operations */
unsigned long t_ka; /* Keep alive interval */
addr sa; /* Socket address to speak to */
unsigned f; /* Flags for the peer */
#define PSF_KXMASK 255u /* Key-exchange flags to set */
#define PSF_MOBILE 256u /* Address may change rapidly */
+#define PSF_EPHEM 512u /* Association is ephemeral */
} peerspec;
typedef struct peer_byname {
peer_byaddr *byaddr; /* Lookup-by-address block */
struct ping *pings; /* Pings we're waiting for */
peerspec spec; /* Specifications for this peer */
+ int afix; /* Index of address family */
tunnel *t; /* Tunnel for local packets */
char *ifname; /* Interface name for tunnel */
keyset *ks; /* List head for keysets */
typedef struct peer_iter { sym_iter i; } peer_iter;
+typedef struct udpsocket {
+ sel_file sf; /* Selector for the socket */
+ unsigned port; /* Chosen port number */
+} udpsocket;
+
typedef struct ping {
struct ping *next, *prev; /* Links to next and previous */
peer *p; /* Peer so we can free it */
typedef struct admin_resop {
admin_bgop bg; /* Background operation header */
char *addr; /* Hostname to be resolved */
+#ifdef HAVE_LIBADNS
+ adns_query q;
+#else
bres_client r; /* Background resolver task */
+#endif
sel_timer t; /* Timer for resolver */
addr sa; /* Socket address */
+ unsigned port; /* Port number chosen */
size_t sasz; /* Socket address size */
void (*func)(struct admin_resop *, int); /* Handler */
} admin_resop;
extern sel_state sel; /* Global I/O event state */
extern octet buf_i[PKBUFSZ], buf_o[PKBUFSZ], buf_t[PKBUFSZ], buf_u[PKBUFSZ];
-extern const tunnel_ops *tunnels[]; /* Table of tunnels (0-term) */
-extern const tunnel_ops *tun_default; /* Default tunnel to use */
+extern udpsocket udpsock[NADDRFAM]; /* The master UDP sockets */
extern kdata *master; /* Default private key */
-extern const char *tag_priv; /* Default private key tag */
+extern char *tag_priv; /* Default private key tag */
#ifndef NTRACE
extern const trace_opt tr_opts[]; /* Trace options array */
extern int km_reload(void);
+/* --- @km_clear@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Forget the currently loaded keyrings. The @master@ key will
+ * be cleared, but other keys already loaded will continue to
+ * exist until their reference count drops to zero. Call
+ * @km_init@ to make everything work again.
+ */
+
+extern void km_clear(void);
+
/* --- @km_findpub@, @km_findpriv@ --- *
*
* Arguments: @const char *tag@ = key tag to load
extern int kx_setup(keyexch */*kx*/, peer */*p*/,
keyset **/*ks*/, unsigned /*f*/);
+/* --- @kx_init@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Initializes the key-exchange logic.
+ */
+
+extern void kx_init(void);
+
/*----- Keysets and symmetric cryptography --------------------------------*/
/* --- @ks_drop@ --- *
*
* * "?PEER" PEER -- peer's name
*
- * * "?ERRNO" ERRNO -- system error code
+ * * "?ERR" CODE -- system error code
+ *
+ * * "?ERRNO" -- system error code from @errno@
*
* * "[!]..." ... -- @dstr_putf@-like string as single token
*/
*
* Returns: ---
*
- * Use: Creates a new admin connection.
+ * Use: Creates a new admin connection. It's safe to call this
+ * before @a_init@ -- and, indeed, this makes sense if you also
+ * call @a_switcherr@ to report initialization errors through
+ * the administration machinery.
*/
extern void a_create(int /*fd_in*/, int /*fd_out*/, unsigned /*f*/);
-/* --- @a_quit@ --- *
- *
- * Arguments: ---
- *
- * Returns: ---
- *
- * Use: Shuts things down nicely.
- */
-
-extern void a_quit(void);
-
/* --- @a_preselect@ --- *
*
* Arguments: ---
extern void a_daemon(void);
+/* --- @a_listen@ --- *
+ *
+ * Arguments: @const char *name@ = socket name to create
+ * @uid_t u@ = user to own the socket
+ * @gid_t g@ = group to own the socket
+ * @mode_t m@ = permissions to set on the socket
+ *
+ * Returns: ---
+ *
+ * Use: Creates the admin listening socket.
+ */
+
+extern void a_listen(const char */*sock*/,
+ uid_t /*u*/, gid_t /*g*/, mode_t /*m*/);
+
+/* --- @a_unlisten@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Stops listening to the administration socket and removes it.
+ */
+
+extern void a_unlisten(void);
+
+/* --- @a_switcherr@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Arrange to report warnings, trace messages, etc. to
+ * administration clients rather than the standard-error stream.
+ *
+ * Obviously this makes no sense unless there is at least one
+ * client established. Calling @a_listen@ won't help with this,
+ * because the earliest a new client can connect is during the
+ * first select-loop iteration, which is too late: some initial
+ * client must have been added manually using @a_create@.
+ */
+
+extern void a_switcherr(void);
+
+/* --- @a_signals@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Establishes handlers for the obvious signals.
+ */
+
+extern void a_signals(void);
+
/* --- @a_init@ --- *
*
* Arguments: @const char *sock@ = socket name to create
* Use: Creates the admin listening socket.
*/
-extern void a_init(const char */*sock*/,
- uid_t /*u*/, gid_t /*g*/, mode_t /*m*/);
+extern void a_init(void);
/*----- Mapping with addresses as keys ------------------------------------*/
extern buf *p_txstart(peer */*p*/, unsigned /*msg*/);
+/* --- @p_txaddr@ --- *
+ *
+ * Arguments: @const addr *a@ = recipient address
+ * @const void *p@ = pointer to packet to send
+ * @size_t sz@ = length of packet
+ *
+ * Returns: Zero if successful, nonzero on error.
+ *
+ * Use: Sends a packet to an address which (possibly) isn't a current
+ * peer.
+ */
+
+extern int p_txaddr(const addr */*a*/, const void */*p*/, size_t /*sz*/);
+
/* --- @p_txend@ --- *
*
* Arguments: @peer *p@ = pointer to peer block
extern const addr *p_addr(peer */*p*/);
+/* --- @p_bind@ --- *
+ *
+ * Arguments: @struct addrinfo *ailist@ = addresses to bind to
+ *
+ * Returns: ---
+ *
+ * Use: Binds to the main UDP sockets.
+ */
+
+extern void p_bind(struct addrinfo */*ailist*/);
+
+/* --- @p_unbind@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Unbinds the UDP sockets. There must not be any active peers,
+ * and none can be created until the sockets are rebound.
+ */
+
+extern void p_unbind(void);
+
/* --- @p_init@ --- *
*
- * Arguments: @struct in_addr addr@ = address to bind to
- * @unsigned port@ = port number to listen to
+ * Arguments: ---
*
* Returns: ---
*
- * Use: Initializes the peer system; creates the socket.
+ * Use: Initializes the peer system.
*/
-extern void p_init(struct in_addr /*addr*/, unsigned /*port*/);
+extern void p_init(void);
-/* --- @p_port@ --- *
+/* --- @p_addtun@ --- *
+ *
+ * Arguments: @const tunnel_ops *tops@ = tunnel ops to add
+ *
+ * Returns: ---
+ *
+ * Use: Adds a tunnel class to the list of known classes. If there
+ * is no current default tunnel, then this one is made the
+ * default.
+ *
+ * Does nothing if the tunnel class is already known. So adding
+ * a bunch of tunnels takes quadratic time, but there will be
+ * too few to care about.
+ */
+
+extern void p_addtun(const tunnel_ops */*tops*/);
+
+/* --- @p_setdflttun@ --- *
+ *
+ * Arguments: @const tunnel_ops *tops@ = tunnel ops to set
+ *
+ * Returns: ---
+ *
+ * Use: Sets the default tunnel. It must already be registered. The
+ * old default is forgotten.
+ */
+
+extern void p_setdflttun(const tunnel_ops */*tops*/);
+
+/* --- @p_dflttun@ --- *
*
* Arguments: ---
*
- * Returns: Port number used for socket.
+ * Returns: A pointer to the current default tunnel operations, or null
+ * if no tunnels are defined.
+ */
+
+extern const tunnel_ops *p_dflttun(void);
+
+/* --- @p_findtun@ --- *
+ *
+ * Arguments: @const char *name@ = tunnel name
+ *
+ * Returns: Pointer to the tunnel operations, or null.
+ *
+ * Use: Finds the operations for a named tunnel class.
+ */
+
+extern const tunnel_ops *p_findtun(const char */*name*/);
+
+/* --- @p_mktuniter@ --- *
+ *
+ * Arguments: @tuniter *i@ = pointer to iterator to initialize
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a tunnel iterator.
*/
-unsigned p_port(void);
+extern void p_mktuniter(tun_iter */*i*/);
+
+/* --- @p_nexttun@ --- *
+ *
+ * Arguments: @tuniter *i@ = pointer to iterator
+ *
+ * Returns: Pointer to the next tunnel's operations, or null.
+ */
+
+extern const tunnel_ops *p_nexttun(tun_iter */*i*/);
+
+/* --- @FOREACH_TUN@ --- *
+ *
+ * Arguments: @tops@ = name to bind to each tunnel
+ * @stuff@ = thing to do for each item
+ *
+ * Use: Does something for each known tunnel class.
+ */
+
+#define FOREACH_TUN(tops, stuff) do { \
+ tun_iter i_; \
+ const tunnel_ops *tops; \
+ for (p_mktuniter(&i_); (tops = p_nexttun(&i_)) != 0; ) stuff; \
+} while (0)
/* --- @p_create@ --- *
*
/* --- @p_destroy@ --- *
*
* Arguments: @peer *p@ = pointer to a peer
+ * @int bye@ = say goodbye to the peer?
*
* Returns: ---
*
* Use: Destroys a peer.
*/
-extern void p_destroy(peer */*p*/);
+extern void p_destroy(peer */*p*/, int /*bye*/);
+
+/* --- @p_destroyall@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Destroys all of the peers, saying goodbye.
+ */
+
+extern void p_destroyall(void);
/* --- @FOREACH_PEER@ --- *
*
extern peer *p_next(peer_iter */*i*/);
+/*----- The interval timer ------------------------------------------------*/
+
+/* --- @iv_addreason@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Adds an `interval timer reason'; if there are no others, the
+ * interval timer is engaged.
+ */
+
+extern void iv_addreason(void);
+
+/* --- @iv_rmreason@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Removes an interval timer reason; if there are none left, the
+ * interval timer is disengaged.
+ */
+
+extern void iv_rmreason(void);
+
+/*----- The main loop -----------------------------------------------------*/
+
+/* --- @lp_init@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Initializes the main loop. Most importantly, this sets up
+ * the select multiplexor that everything else hooks onto.
+ */
+
+extern void lp_init(void);
+
+/* --- @lp_end@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: ---
+ *
+ * Use: Requests an exit from the main loop.
+ */
+
+extern void lp_end(void);
+
+/* --- @lp_run@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: Zero on successful termination; @-1@ if things went wrong.
+ *
+ * Use: Cranks the main loop until it should be cranked no more.
+ */
+
+extern int lp_run(void);
+
/*----- Tunnel drivers ----------------------------------------------------*/
#ifdef TUN_LINUX
extern int mystrieq(const char */*x*/, const char */*y*/);
+/* --- @afix@ --- *
+ *
+ * Arguments: @int af@ = an address family code
+ *
+ * Returns: The index of the address family's record in @aftab@, or @-1@.
+ */
+
+extern int afix(int af);
+
/* --- @addrsz@ --- *
*
* Arguments: @const addr *a@ = a network address
extern socklen_t addrsz(const addr */*a*/);
+/* --- @getport@, @setport@ --- *
+ *
+ * Arguments: @addr *a@ = a network address
+ * @unsigned port@ = port number to set
+ *
+ * Returns: ---
+ *
+ * Use: Retrieves or sets the port number in an address structure.
+ */
+
+extern unsigned getport(addr */*a*/);
+extern void setport(addr */*a*/, unsigned /*port*/);
+
/* --- @seq_reset@ --- *
*
* Arguments: @seqwin *s@ = sequence-checking window