spiped-1.3.1/000755 001751 001751 00000000000 12132206317 014431 5ustar00cpercivacperciva000000 000000 spiped-1.3.1/spiped/000755 001751 001751 00000000000 12132206317 015715 5ustar00cpercivacperciva000000 000000 spiped-1.3.1/spipe/000755 001751 001751 00000000000 12132206317 015551 5ustar00cpercivacperciva000000 000000 spiped-1.3.1/BUILDING000644 001751 001751 00000002673 12132205630 015556 0ustar00cpercivacperciva000000 000000 To build and install spiped, run: # make BINDIR=/path/to/target/directory install To install man pages, add MAN1DIR=/path/to/man.1/directory to the command line (e.g., MAN1DIR=/usr/local/man/man1 on FreeBSD). Spiped should build and run on any IEEE Std 1003.1 (POSIX) compliant system which 1. Includes the Software Development Utilities option, 2. Has OpenSSL available via -lcrypto and #include , and 3. Provides /dev/urandom. On some platforms (Solaris, maybe others), additional compiler and/or linker options are required to find OpenSSL or system libraries; these can be provided by adding e.g., CFLAGS="-I/path/to/openssl/headers" (compiler option) or LDADD_EXTRA="-L/usr/sfw/lib -lsocket -lnsl" (linker option) to the make command line. On some platforms (OpenBSD prior to 5.4, and possibly others) you will need to add #include at the start of lib/dnsthread/dnsthread.c lib/util/sock_util.c proto/proto_conn.c spipe/main.c spipe/pushbits.c due to a POSIX-compliance bug on those platforms. On some platforms (mostly Linuxes) it is possible to install OpenSSL libaries wihout the associated header files; the header files are usually in packages named "openssl-devel", "libssl-dev", or similar. If your OS provides random bytes via some mechanism other than /dev/urandom, please make local changes to lib/util/entropy.c and notify the author. If spiped fails to build or run for other reasons, please notify the author. spiped-1.3.1/CHANGELOG000644 001751 001751 00000002646 12132205630 015650 0ustar00cpercivacperciva000000 000000 spiped-1.3.1 * Fix build by adding missing #include. * Minor code cleanups. spiped-1.3.0 * Bug fix: spiped now correctly closes connections which have been reset; in earlier versions spiped could erronously hold "dead" connections open as long as they remained idle. * Man pages added. * Protocol-layer keep-alives are now enabled by default. * New option -j (spipe/spiped): Disable protocol-layer keep-alives. * In spiped the target address is now re-resolved every 60 seconds by default. * New option -R (spiped): Do not re-resolve target address. * New option -r (spiped): Re-resolve target address every seconds. spiped-1.2.2 * Build fixes for some strictly POSIX-conforming platforms. * Detect and work around compilers which are POSIX-noncompliant in their handling of -rt and -lxnet options. * Minor documentation and typo fixes. spiped-1.2.1 * Fix build by adding missing #include. spiped-1.2.0 * New utility "spipe": A client for the spiped protocol, handling a single connection with standard input/output as one end. * Code rearrangement with no functional consequences. * Minor bug and documentation fixes. spiped-1.1.0 * New option -D: Wait until DNS lookups succeed. * New option -F: Don't daemonize. * Use SO_REUSEADDR to avoid 'socket address already in use' error (most importantly, if spiped is killed and restarted). * Minor bug and style fixes. spiped-1.0.0 * Initial release spiped-1.3.1/COPYRIGHT000644 001751 001751 00000003021 12132205630 015715 0ustar00cpercivacperciva000000 000000 The included code and documentation ("spiped") is distributed under the following terms: Copyright 2005-2013 Colin Percival. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. In addition to the above, some files are: Copyright 2012 Andreas Olsson and distributed under the same terms. Such files contain individual copyright statements and licenses. spiped-1.3.1/README000644 001751 001751 00000021431 12132205627 015315 0ustar00cpercivacperciva000000 000000 spiped design ============= Introduction ------------ spiped (pronounced "ess-pipe-dee") is a utility for creating symmetrically encrypted and authenticated pipes between socket addresses, so that one may connect to one address (e.g., a UNIX socket on localhost) and transparently have a connection established to another address (e.g., a UNIX socket on a different system). This is similar to 'ssh -L' functionality, but does not use SSH and requires a pre-shared symmetric key. spipe (pronounced "ess-pipe") is a utility which acts as an spiped protocol client (i.e., connects to an spiped daemon), taking input from the standard input and writing data read back to the standard output. Note that spiped: 1. Requires a strong key file: The file specified via the -k option should have at least 256 bits of entropy. ('dd if=/dev/urandom bs=32 count=1' is your friend.) 2. Requires strong entropy from /dev/urandom. (Make sure your kernel's random number generator is seeded at boot time!) 3. Does not provide any protection against information leakage via packet timing: Running telnet over spiped will protect a password from being directly read from the network, but will not obscure the typing rhythm. 4. Can significantly increase bandwidth usage for interactive sessions: It sends data in packets of 1024 bytes, and pads smaller messages up to this length, so a 1 byte write could be expanded to 1024 bytes if it cannot be coalesced with adjacent bytes. 5. Uses a symmetric key -- so anyone who can connect to an spiped "server" is also able to impersonate it. Example usage ------------- To set up an encrypted and authenticated pipe for sending email between two systems (in the author's case, from many systems around the internet to his central SMTP server, which then relays email to the rest of the world), one might run # dd if=/dev/urandom bs=32 count=1 of=keyfile # spiped -d -s '[0.0.0.0]:8025' -t '[127.0.0.1]:25' -k keyfile on a server and after copying keyfile to the local system, run # spiped -e -s '[127.0.0.1]:25' -t $SERVERNAME:8025 -k keyfile at which point mail delivered via localhost:25 on the local system will be securely transmitted to port 25 on the server. You can also use spiped to protect SSH servers from attackers: Since data is authenticated before being forwarded to the target, this can allow you to SSH to a host while protecting you in the event that someone finds an exploitable bug in the SSH daemon -- this serves the same purpose as port knocking or a firewall which restricts source IP addresses which can connect to SSH. On the SSH server, run # dd if=/dev/urandom bs=32 count=1 of=/etc/ssh/spiped.key # spiped -d -s '[0.0.0.0]:8022' -t '[127.0.0.1]:22' -k /etc/ssh/spiped.key then copy the server's /etc/ssh/spiped.key to ~/.ssh/spiped_HOSTNAME_key on your local system and add the lines Host HOSTNAME ProxyCommand spipe -t %h:8022 -k ~/.ssh/spiped_%h_key to the ~/.ssh/config file. This will cause "ssh HOSTNAME" to automatically connect using the spipe client via the spiped daemon; you can then firewall off all incoming traffic on port tcp/22. For a detailed list of the command-line options to spiped and spipe, see the README files in the respective subdirectories. Security requirements --------------------- The user is responsible for ensuring that: 1. The key file contains 256 or more bits of entropy. 2. The same key file is not used for more than 2^64 connections. 3. Any individual connection does not transmit more than 2^64 bytes. Encrypted protocol ------------------ The client and server share a key file with 256 or more bits of entropy. On launch, they read the key file and compute K = SHA256(key file). When a connection is established: C1. The client generates a 256-bit random value nonce_C and sends it. S1. The server generates a 256-bit random value nonce_S and sends it. C2. The client receives a 256-bit value nonce_S. S2. The server receives a 256-bit value nonce_C. C3/S3. Both parties now compute the 512-bit value dk_1 = PBKDF2-SHA256(K, nonce_C || nonce_S, 1) and parse it as a pair of 256-bit values dhmac_C || dhmac_S = dk_1. C4. The client picks* a value x_C and computes** y_C = 2^x_C mod p, where p is the Diffie-Hellman "group #14" modulus, and h_C = HMAC-SHA256(dhmac_C, y_C). The client sends y_C || h_C to the server. S4. The server receives a 2304-bit value which it parses as y_C || h_C, where y_C is 2048 bits and h_C is 256 bits; and drops the connection if h_C is not equal to HMAC-SHA256(dhmac_C, y_C) or y_C >= p. S5. The server picks* a value x_S and computes** y_S = 2^x_S mod p and h_S = HMAC-SHA256(dhmac_S, y_S). The server sends y_S || h_S to the client. C5. The client receives a 2304-bit value which it parses as y_S || h_S, where y_S is 2048 bits and h_S is 256 bits; and drops the connection if h_S is not equal to HMAC-SHA256(dhmac_S, y_S) or y_S >= p. C6. The client computes** y_SC = y_S^x_C mod p. S6. The server computes** y_SC = y_C^x_S mod p. (Note that these two compute values are identical.) C7/S7. Both parties now compute the 1024-bit value dk_2 = PBKDF2-SHA256(K, nonce_C || nonce_S || y_SC, 1) and parse it as a 4-tuple of 256-bit values E_C || H_C || E_S || H_S. Thereafter, the client and server exchange 1060-byte packets P generated from plaintext messages M of 1--1024 bytes msg_padded = M || ( 0x00 x (1024 - length(M))) || bigendian32(length(M)) msg_encrypted = AES256-CTR(E, msg_padded, packet#) P = msg_encrypted || HMAC-SHA256(H, msg_encrypted || bigendian64(packet#)) where E and H are E_C and H_C or E_S and H_S depending on whether the packet is being sent by the client or the server, and AES256-CTR is computed with nonce equal to the packet #, which starts at zero and increments for each packet sent in the same direction. * The values x_C, x_S picked must either be 0 (if forward perfect secrecy is not desired) or have 256 bits of entropy (if forward perfect secrecy is desired). ** The values y_C, y_S, and y_SC are 2048 bits and big-endian. Security proof -------------- 1. Under the random oracle model, K has at least 255 bits of entropy (it's a 256-bit hash computed from a value with at least 256 bits of entropy). 2. Provided that at least one party is following the protocol and the key file has been used for fewer than 2^64 connections, the probability of the tuple (K, nonce_C, nonce_S) being non-unique is less than 2^(-192). 3. Under the random oracle model, the probability of an attacker without access to K guessing either of dhmac_C and dhmac_S is less than P(attacker guesses K) + P(the tuple has been input to the oracle before) + P(the attacker directly guesses), which is less than 2^(-255) + 2^(-192) + 2^(-255) = 2^(-192) + 2^(-254). 4. Consequently, in order for an attacker to convince a protocol-obeying party that a tuple (y, h) is legitimate, the attacker must do at least 2^190 expected work (which we consider to be computationally infeasible and do not consider any further). 5. If one of the parties opts to not have perfect forward secrecy, then the value y_SC will be equal to 1 and dk_2 will have the same security properties as dk_1, i.e., it will be computationally infeasible for an attacker without access to K to compute dk_2. 6. If both parties opt for perfect forward secrecy, an attacker who can compute y_SC has solved a Diffie-Hellman problem over the 2048-bit group #14, which is (under the CDH assumption) computationally infeasible. 7. Consequently, if both parties opt for perfect forward secrecy, an attacker who obtains access to K after the handshake has completed will continue to be unable to compute dk_2 from information exchanged during the handshake. 8. Under the random oracle model, the packets P are indistinguishable from random 1060-byte packets; thus no information about the keys used or the plaintext being transmitted is revealed by post-key-exchange communications. 9. Because the values (msg_encrypted || bigendian(packet#)) are distinct for each packet, under the random oracle model it is infeasible for an attacker without access to the value H to generate a packet which will be accepted as valid. Code layout ----------- spiped/* -- Code specific to the spiped utility. main.c -- Command-line parsing, initialization, and event loop. dispatch.c -- Accepts connections and hands them off to protocol code. spipe/* -- Code specific to the spipe utility. main.c -- Command-line parsing, initialization, and event loop. pushbits.c -- Copies data between standard input/output and a socket. proto/* -- Implements the spiped protocol. _conn.c -- Manages the lifecycle of a connection. _handshake.c -- Performs the handshaking portion of the protocol. _pipe.c -- Performs the data-shuttling portion of the protocol. _crypt.c -- Does the cryptographic bits needed by _handshake and _pipe. lib/* -- Library code (mostly originating from tarsnap and kivaloo). spiped-1.3.1/STYLE000644 001751 001751 00000011517 12132205630 015256 0ustar00cpercivacperciva000000 000000 Code style ========== In general, FreeBSD style(9) should be followed unless it is irrelevant (e.g., $FreeBSD$ tags). Functions with external linkage are declared like this: /** * module_func(arg1, arg2): * Description of what the function does, referring to arguments as * ${arg1} or suchlike. */ int module_func(void *, int); The identical comment appears in the C file where the function is defined. Static functions may have the above form of comment, or simply a /* Brief description of what the function does. */ line before the function. In general, functions should return (int)(-1) or NULL to indicate error. Errors should be printed via warnp (if errno is relevant) or warn0 (if errno is not relevant) when they are first detected and also at higher levels where useful. As an exception to this, malloc failures (i.e., errno = ENOMEM) can result in failure being passed back up the call chain without being printed immediately. (Naturally, other errors can be passed back where a function definition so specifies; e.g., ENOENT in cases where a file not existing is not erronous.) The first statement in main(), after variable declarations, should be "WARNP_INIT;" in order to set the program name used for printing warnings. In general, functions should be structured with one return statement per status, e.g., one return() for success and one return() for failure. Errors should be handled by using goto to enter the error return path, e.g., int foo(int bar) { if (something fails) goto err0; /* ... */ if (something else fails) goto err1; /* ... */ if (yet another operation fails) goto err2; /* Success! */ return (0); err2: /* Clean up something. */ err1: /* Clean up something else. */ err0: /* Failure! */ return (-1); } As an exception to the above, if there is only one way for the function to fail, the idioms return (baz(bar)); and int rc; rc = baz(bar); /* ... cleanup code here ... */ return (rc); are allowed; furthermore, in cases such as foo_free(), the idiom if (we shouldn't do anything) return; is preferred over if (we shouldn't do anything) goto done; at the start of a function. Headers should be included in the following groups, with a blank line after each (non-empty) group: 1. , with first followed by others alphabetically. 2. , in alphabetical order. 3. <*.h>, in alphabetical order. 4. header files from /lib/, in alphabetical order. 5. header files from the program being built, in alphabetical order. 6. header files (usually just one) defining the interface for this C file. If ssize_t is needed, should be included to provide it. If size_t is needed, should be included to provide it unless , , , or is already required. If the C99 integer types (uint8_t, int64_t, etc.) are required, should be included to provide them unless is already required. The type 'char' should only be used to represent human-readable characters (input from users, output to users, pathnames, et cetera). The type 'char *' should normally be a NUL-terminated string. The types 'signed char' and 'unsigned char' should never be used; C99 integer types should be used instead. When a struct is referenced, the idiom /* Opaque types. */ struct foo; struct bar * bar_from_foo(struct foo *); is preferable to #include "foo.h" /* needed for struct foo */ struct bar * bar_from_foo(struct foo *); unless there is some reason why the internal layout of struct foo is needed (e.g., if struct bar contains a struct foo rather than a struct foo *). Such struct declarations should be sorted alphabetically. The file foo.c should only export symbols of the following forms: foo_* -- most symbols should be of this form. FOO_* / BAR_FOO_* -- allowed in cases where FOO or BAR_FOO is idiomatic (e.g., MD5, HMAC_SHA256). foo() / defoo() / unfoo() -- where "foo" is a verb and this improves code clarity. Functions named foo_free should return void, and foo_free(NULL) should have no effect. If static variables need to be initialized to 0 (or NULL) then they should be explicitly declared that way; implicit initialization should not be used. In non-trivial code, comments should be included which describe in English what is being done by the surrounding code with sufficient detail that if the code were removed, it could be replaced based on reading the comments without requiring any significant creativity. Comments and documentation should be written in en-GB-oed; i.e., with the 'u' included in words such as "honour", "colour", and "neighbour", and the ending '-ize' in words such as "organize" and "realize". The Oxford (aka. serial) comma should be used in lists. Quotation marks should be placed logically, i.e., not including punctuation marks which do not form a logical part of the quoted text. spiped-1.3.1/POSIX/000755 001751 001751 00000000000 12132205630 015330 5ustar00cpercivacperciva000000 000000 spiped-1.3.1/lib/000755 001751 001751 00000000000 12132205630 015174 5ustar00cpercivacperciva000000 000000 spiped-1.3.1/proto/000755 001751 001751 00000000000 12132205630 015571 5ustar00cpercivacperciva000000 000000 spiped-1.3.1/Makefile000644 001751 001751 00000001346 12132206317 016075 0ustar00cpercivacperciva000000 000000 .POSIX: PROGS= spiped spipe BINDIR_DEFAULT= /usr/local/bin CFLAGS_DEFAULT= -O2 all: if [ -z "${CFLAGS}" ]; then \ CFLAGS=${CFLAGS_DEFAULT}; \ else \ CFLAGS="${CFLAGS}"; \ fi; \ LDADD_POSIX=`export CC=${CC}; cd POSIX && command -p sh posix-l.sh`; \ for D in ${PROGS}; do \ ( cd $${D} && \ make CFLAGS="$${CFLAGS}" \ LDADD_POSIX="$${LDADD_POSIX}" all ) || \ exit 2; \ done install: all if [ -z "${BINDIR}" ]; then \ BINDIR=${BINDIR_DEFAULT}; \ else \ BINDIR="${BINDIR}"; \ fi; \ for D in ${PROGS}; do \ ( cd $${D} && make BINDIR="$${BINDIR}" install ) || exit 2; \ done clean: for D in ${PROGS}; do \ ( cd $${D} && make clean ) || exit 2; \ done spiped-1.3.1/proto/proto_pipe.c000644 001751 001751 00000010505 12132205630 020116 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include "network.h" #include "proto_crypt.h" #include "proto_pipe.h" struct pipe_cookie { int (* callback)(void *); void * cookie; int * status; int s_in; int s_out; int decr; struct proto_keys * k; uint8_t dbuf[PCRYPT_MAXDSZ]; uint8_t ebuf[PCRYPT_ESZ]; void * read_cookie; void * write_cookie; ssize_t wlen; }; static int callback_pipe_read(void *, ssize_t); static int callback_pipe_write(void *, ssize_t); /** * proto_pipe(s_in, s_out, decr, k, status, callback, cookie): * Read bytes from ${s_in} and write them to ${s_out}. If ${decr} is non-zero * then use ${k} to decrypt the bytes; otherwise use ${k} to encrypt them. * If EOF is read, set ${status} to 0, and if an error is encountered set * ${status} to -1; in either case, invoke ${callback}(${cookie}). Return a * cookie which can be passed to proto_pipe_cancel. */ void * proto_pipe(int s_in, int s_out, int decr, struct proto_keys * k, int * status, int (* callback)(void *), void * cookie) { struct pipe_cookie * P; /* Bake a cookie. */ if ((P = malloc(sizeof(struct pipe_cookie))) == NULL) goto err0; P->callback = callback; P->cookie = cookie; P->status = status; P->s_in = s_in; P->s_out = s_out; P->decr = decr; P->k = k; P->read_cookie = NULL; P->write_cookie = NULL; /* Start reading. */ if (P->decr) { if ((P->read_cookie = network_read(P->s_in, P->ebuf, PCRYPT_ESZ, PCRYPT_ESZ, callback_pipe_read, P)) == NULL) goto err1; } else { if ((P->read_cookie = network_read(P->s_in, P->dbuf, PCRYPT_MAXDSZ, 1, callback_pipe_read, P)) == NULL) goto err1; } /* Success! */ return (P); err1: free(P); err0: /* Failure! */ return (NULL); } /* Some data has been read. */ static int callback_pipe_read(void * cookie, ssize_t len) { struct pipe_cookie * P = cookie; /* This read is no longer in progress. */ P->read_cookie = NULL; /* Did we read EOF? */ if (len == 0) goto eof; /* Did the read fail? */ if (len == -1) goto fail; /* Did a packet read end prematurely? */ if ((P->decr) && (len < PCRYPT_ESZ)) goto fail; /* Encrypt or decrypt the data. */ if (P->decr) { if ((P->wlen = proto_crypt_dec(P->ebuf, P->dbuf, P->k)) == -1) goto fail; } else { proto_crypt_enc(P->dbuf, len, P->ebuf, P->k); P->wlen = PCRYPT_ESZ; } /* Write the encrypted or decrypted data. */ if (P->decr) { if ((P->write_cookie = network_write(P->s_out, P->dbuf, P->wlen, P->wlen, callback_pipe_write, P)) == NULL) goto err0; } else { if ((P->write_cookie = network_write(P->s_out, P->ebuf, P->wlen, P->wlen, callback_pipe_write, P)) == NULL) goto err0; } /* Success! */ return (0); fail: /* Record that this connection is broken. */ *(P->status) = -1; /* Inform the upstream that our status has changed. */ return ((P->callback)(P->cookie)); eof: /* We aren't going to write any more. */ shutdown(P->s_out, SHUT_WR); /* Record that we have reached EOF. */ *(P->status) = 0; /* Inform the upstream that our status has changed. */ return ((P->callback)(P->cookie)); err0: /* Failure! */ return (-1); } static int callback_pipe_write(void * cookie, ssize_t len) { struct pipe_cookie * P = cookie; /* This write is no longer in progress. */ P->write_cookie = NULL; /* Did we fail to write everything? */ if (len < P->wlen) goto fail; /* Launch another read. */ if (P->decr) { if ((P->read_cookie = network_read(P->s_in, P->ebuf, PCRYPT_ESZ, PCRYPT_ESZ, callback_pipe_read, P)) == NULL) goto err0; } else { if ((P->read_cookie = network_read(P->s_in, P->dbuf, PCRYPT_MAXDSZ, 1, callback_pipe_read, P)) == NULL) goto err0; } /* Success! */ return (0); fail: /* Record that this connection is broken. */ *(P->status) = -1; /* Inform the upstream that our status has changed. */ return ((P->callback)(P->cookie)); err0: /* Failure! */ return (-1); } /** * proto_pipe_cancel(cookie): * Shut down the pipe created by proto_pipe for which ${cookie} was returned. */ void proto_pipe_cancel(void * cookie) { struct pipe_cookie * P = cookie; /* If a read or write is in progress, cancel it. */ if (P->read_cookie) network_read_cancel(P->read_cookie); if (P->write_cookie) network_write_cancel(P->write_cookie); /* Free the cookie. */ free(P); } spiped-1.3.1/proto/proto_conn.c000644 001751 001751 00000020663 12132205630 020124 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include "events.h" #include "network.h" #include "sock.h" #include "proto_handshake.h" #include "proto_pipe.h" #include "proto_crypt.h" #include "proto_conn.h" struct conn_state { int (* callback_dead)(void *); void * cookie; struct sock_addr ** sas; int decr; int nofps; int nokeepalive; const struct proto_secret * K; double timeo; int s; int t; void * connect_cookie; void * connect_timeout_cookie; void * handshake_cookie; void * handshake_timeout_cookie; struct proto_keys * k_f; struct proto_keys * k_r; void * pipe_f; void * pipe_r; int stat_f; int stat_r; }; static int callback_connect_done(void *, int); static int callback_connect_timeout(void *); static int callback_handshake_done(void *, struct proto_keys *, struct proto_keys *); static int callback_handshake_timeout(void *); static int callback_pipestatus(void *); /* Start a handshake. */ static int starthandshake(struct conn_state * C, int s, int decr) { /* Start the handshake timer. */ if ((C->handshake_timeout_cookie = events_timer_register_double( callback_handshake_timeout, C, C->timeo)) == NULL) goto err0; /* Start the handshake. */ if ((C->handshake_cookie = proto_handshake(s, decr, C->nofps, C->K, callback_handshake_done, C)) == NULL) goto err1; /* Success! */ return (0); err1: events_timer_cancel(C->handshake_timeout_cookie); C->handshake_timeout_cookie = NULL; err0: /* Failure! */ return (-1); } /* Launch the two pipes. */ static int launchpipes(struct conn_state * C) { int on = C->nokeepalive ? 0 : 1; /* * Attempt to turn keepalives on or off as requested. We ignore * failures here since the sockets might not be of a type for which * SO_KEEPALIVE is valid -- it is a socket level option, but protocol * specific. In particular, it has no sensible meaning for UNIX * sockets. */ (void)setsockopt(C->s, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); (void)setsockopt(C->t, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); /* Create two pipes. */ if ((C->pipe_f = proto_pipe(C->s, C->t, C->decr, C->k_f, &C->stat_f, callback_pipestatus, C)) == NULL) goto err0; if ((C->pipe_r = proto_pipe(C->t, C->s, !C->decr, C->k_r, &C->stat_r, callback_pipestatus, C)) == NULL) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /* Drop a connection. */ static int dropconn(struct conn_state * C) { int rc; /* Close the incoming connection. */ close(C->s); /* Close the outgoing connection if it is open. */ if (C->t != -1) close(C->t); /* Stop connecting if a connection is in progress. */ if (C->connect_cookie != NULL) network_connect_cancel(C->connect_cookie); /* Free the target addresses if we haven't already done so. */ sock_addr_freelist(C->sas); /* Stop handshaking if a handshake is in progress. */ if (C->handshake_cookie != NULL) proto_handshake_cancel(C->handshake_cookie); /* Kill timeouts if they are pending. */ if (C->connect_timeout_cookie != NULL) events_timer_cancel(C->connect_timeout_cookie); if (C->handshake_timeout_cookie != NULL) events_timer_cancel(C->handshake_timeout_cookie); /* Free protocol keys. */ proto_crypt_free(C->k_f); proto_crypt_free(C->k_r); /* Shut down pipes. */ if (C->pipe_f != NULL) proto_pipe_cancel(C->pipe_f); if (C->pipe_r != NULL) proto_pipe_cancel(C->pipe_r); /* Notify the upstream that we've dropped a connection. */ rc = (C->callback_dead)(C->cookie); /* Free the connection cookie. */ free(C); /* Return success/fail status. */ return (rc); } /** * proto_conn_create(s, sas, decr, nofps, nokeepalive, K, timeo, * callback_dead, cookie): * Create a connection with one end at ${s} and the other end connecting to * the target addresses ${sas}. If ${decr} is 0, encrypt the outgoing data; * if ${decr} is nonzero, decrypt the outgoing data. If ${nofps} is non-zero, * don't use perfect forward secrecy. Enable transport layer keep-alives (if * applicable) on both sockets if and only if ${nokeepalive} is zero. Drop the * connection if the handshake or connecting to the target takes more than * ${timeo} seconds. When the connection is dropped, invoke * ${callback_dead}(${cookie}). Free ${sas} once it is no longer needed. */ int proto_conn_create(int s, struct sock_addr ** sas, int decr, int nofps, int nokeepalive, const struct proto_secret * K, double timeo, int (* callback_dead)(void *), void * cookie) { struct conn_state * C; /* Bake a cookie for this connection. */ if ((C = malloc(sizeof(struct conn_state))) == NULL) goto err0; C->callback_dead = callback_dead; C->cookie = cookie; C->sas = sas; C->decr = decr; C->nofps = nofps; C->nokeepalive = nokeepalive; C->K = K; C->timeo = timeo; C->s = s; C->t = -1; C->connect_cookie = NULL; C->handshake_cookie = NULL; C->connect_timeout_cookie = C->handshake_timeout_cookie = NULL; C->k_f = C->k_r = NULL; C->pipe_f = C->pipe_r = NULL; C->stat_f = C->stat_r = 1; /* Start the connect timer. */ if ((C->connect_timeout_cookie = events_timer_register_double( callback_connect_timeout, C, C->timeo)) == NULL) goto err1; /* Connect to target. */ if ((C->connect_cookie = network_connect(C->sas, callback_connect_done, C)) == NULL) goto err2; /* If we're decrypting, start the handshake. */ if (C->decr) { if (starthandshake(C, C->s, C->decr)) goto err3; } /* Success! */ return (0); err3: network_connect_cancel(C->connect_cookie); err2: events_timer_cancel(C->connect_timeout_cookie); err1: free(C); err0: /* Failure! */ return (-1); } /* We have connected to the target. */ static int callback_connect_done(void * cookie, int t) { struct conn_state * C = cookie; /* This connection attempt is no longer pending. */ C->connect_cookie = NULL; /* Don't need the target address any more. */ sock_addr_freelist(C->sas); C->sas = NULL; /* We beat the clock. */ events_timer_cancel(C->connect_timeout_cookie); C->connect_timeout_cookie = NULL; /* Did we manage to connect? */ if ((C->t = t) == -1) return (dropconn(C)); /* If we're encrypting, start the handshake. */ if (!C->decr) { if (starthandshake(C, C->t, C->decr)) goto err1; } /* If we have connections and keys, start shuttling data. */ if ((C->t != -1) && (C->k_f != NULL) && (C->k_r != NULL)) { if (launchpipes(C)) goto err1; } /* Success! */ return (0); err1: dropconn(C); /* Failure! */ return (-1); } /* Connecting to the target took too long. */ static int callback_connect_timeout(void * cookie) { struct conn_state * C = cookie; /* This timeout is no longer pending. */ C->connect_timeout_cookie = NULL; /* * We could free C->sas here, but from a semantic point of view it * could still be in use by the not-yet-cancelled connect operation. * Instead, we free it in dropconn, after cancelling the connect. */ /* Drop the connection. */ return (dropconn(C)); } /* We have performed the protocol handshake. */ static int callback_handshake_done(void * cookie, struct proto_keys * f, struct proto_keys * r) { struct conn_state * C = cookie; /* The handshake is no longer in progress. */ C->handshake_cookie = NULL; /* We beat the clock. */ events_timer_cancel(C->handshake_timeout_cookie); C->handshake_timeout_cookie = NULL; /* If the protocol handshake failed, drop the connection. */ if ((f == NULL) && (r == NULL)) return (dropconn(C)); /* We should have two keys. */ assert(f != NULL); assert(r != NULL); /* Record the keys so we can free them later. */ C->k_f = f; C->k_r = r; /* If we have connections and keys, start shuttling data. */ if ((C->t != -1) && (C->k_f != NULL) && (C->k_r != NULL)) { if (launchpipes(C)) goto err1; } /* Success! */ return (0); err1: dropconn(C); /* Failure! */ return (-1); } /* The protocol handshake took too long. */ static int callback_handshake_timeout(void * cookie) { struct conn_state * C = cookie; /* This timeout is no longer pending. */ C->handshake_timeout_cookie = NULL; /* Drop the connection. */ return (dropconn(C)); } /* The status of one of the directions has changed. */ static int callback_pipestatus(void * cookie) { struct conn_state * C = cookie; /* If we have an error in either direction, kill the connection. */ if ((C->stat_f == -1) || (C->stat_r == -1)) return (dropconn(C)); /* If both directions have been shut down, kill the connection. */ if ((C->stat_f == 0) && (C->stat_r == 0)) return (dropconn(C)); /* Nothing to do. */ return (0); } spiped-1.3.1/proto/proto_crypt.c000644 001751 001751 00000021511 12132205630 020321 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include "crypto_aesctr.h" #include "crypto_verify_bytes.h" #include "sha256.h" #include "sysendian.h" #include "warnp.h" #include "proto_crypt.h" struct proto_secret { uint8_t K[32]; }; struct proto_keys { AES_KEY k_aes; uint8_t k_hmac[32]; uint64_t pnum; }; /** * mkkeypair(kbuf): * Convert the 64 bytes of ${kbuf} into a protocol key structure. */ static struct proto_keys * mkkeypair(uint8_t kbuf[64]) { struct proto_keys * k; /* Allocate a structure. */ if ((k = malloc(sizeof(struct proto_keys))) == NULL) goto err0; /* Expand the AES key. */ if (AES_set_encrypt_key(&kbuf[0], 256, &k->k_aes)) { warn0("Error in AES_set_encrypt_key"); goto err1; } /* Fill in HMAC key. */ memcpy(k->k_hmac, &kbuf[32], 32); /* The first packet will be packet number zero. */ k->pnum = 0; /* Success! */ return (k); err1: free(k); err0: /* Failure! */ return (NULL); } /** * proto_crypt_secret(filename): * Read the key file ${filename} and return a protocol secret structure. */ struct proto_secret * proto_crypt_secret(const char * filename) { SHA256_CTX ctx; FILE * f; struct proto_secret * K; uint8_t buf[BUFSIZ]; size_t lenread; /* Allocate a protocol secret structure. */ if ((K = malloc(sizeof(struct proto_secret))) == NULL) goto err0; /* Open the file. */ if ((f = fopen(filename, "r")) == NULL) { warnp("Cannot open file: %s", filename); goto err1; } /* Initialize the SHA256 hash context. */ SHA256_Init(&ctx); /* Read the file until we hit EOF. */ while ((lenread = fread(buf, 1, BUFSIZ, f)) > 0) SHA256_Update(&ctx, buf, lenread); /* Did we hit EOF? */ if (! feof(f)) { warnp("Error reading file: %s", filename); goto err2; } /* Close the file. */ fclose(f); /* Compute the final hash. */ SHA256_Final(K->K, &ctx); /* Success! */ return (K); err2: fclose(f); err1: free(K); err0: /* Failure! */ return (NULL); } /** * proto_crypt_dhmac(K, nonce_l, nonce_r, dhmac_l, dhmac_r, decr): * Using the key file hash ${K}, and the local and remote nonces ${nonce_l} * and ${nonce_r}, compute the local and remote diffie-hellman parameter MAC * keys ${dhmac_l} and ${dhmac_r}. If ${decr} is non-zero, "local" == "S" * and "remote" == "C"; otherwise the assignments are opposite. */ void proto_crypt_dhmac(const struct proto_secret * K, const uint8_t nonce_l[PCRYPT_NONCE_LEN], const uint8_t nonce_r[PCRYPT_NONCE_LEN], uint8_t dhmac_l[PCRYPT_DHMAC_LEN], uint8_t dhmac_r[PCRYPT_DHMAC_LEN], int decr) { uint8_t nonce_CS[PCRYPT_NONCE_LEN * 2]; uint8_t dk_1[PCRYPT_DHMAC_LEN * 2]; /* Copy in nonces (in the right order). */ memcpy(&nonce_CS[0], decr ? nonce_r : nonce_l, PCRYPT_NONCE_LEN); memcpy(&nonce_CS[PCRYPT_NONCE_LEN], decr ? nonce_l : nonce_r, PCRYPT_NONCE_LEN); /* Compute dk_1. */ PBKDF2_SHA256(K->K, 32, nonce_CS, PCRYPT_NONCE_LEN * 2, 1, dk_1, PCRYPT_DHMAC_LEN * 2); /* Copy out diffie-hellman parameter MAC keys (in the right order). */ memcpy(decr ? dhmac_r : dhmac_l, &dk_1[0], PCRYPT_DHMAC_LEN); memcpy(decr ? dhmac_l : dhmac_r, &dk_1[PCRYPT_DHMAC_LEN], PCRYPT_DHMAC_LEN); } /** * proto_crypt_dh_validate(yh_r, dhmac_r): * Return non-zero if the value ${yh_r} received from the remote party is not * correctly MACed using the diffie-hellman parameter MAC key ${dhmac_r}, or * if the included y value is >= the diffie-hellman group modulus. */ int proto_crypt_dh_validate(const uint8_t yh_r[PCRYPT_YH_LEN], const uint8_t dhmac_r[PCRYPT_DHMAC_LEN]) { uint8_t hbuf[32]; /* Compute HMAC. */ HMAC_SHA256_Buf(dhmac_r, PCRYPT_DHMAC_LEN, yh_r, CRYPTO_DH_PUBLEN, hbuf); /* Check that the MAC matches. */ if (crypto_verify_bytes(&yh_r[CRYPTO_DH_PUBLEN], hbuf, 32)) return (1); /* Sanity-check the diffie-hellman value. */ return (crypto_dh_sanitycheck(&yh_r[0])); } /** * proto_crypt_dh_generate(yh_l, x, dhmac_l, nofps): * Using the MAC key ${dhmac_l}, generate the MACed diffie-hellman handshake * parameter ${yh_l}. Store the diffie-hellman private value in ${x}. If * ${nofps} is non-zero, skip diffie-hellman generation and use y = 1. */ int proto_crypt_dh_generate(uint8_t yh_l[PCRYPT_YH_LEN], uint8_t x[PCRYPT_X_LEN], const uint8_t dhmac_l[PCRYPT_DHMAC_LEN], int nofps) { /* Are we skipping the diffie-hellman generation? */ if (nofps) { /* Set y_l to a big-endian 1. */ memset(yh_l, 0, CRYPTO_DH_PUBLEN - 1); yh_l[CRYPTO_DH_PUBLEN - 1] = 1; } else { /* Generate diffie-hellman parameters x and y. */ if (crypto_dh_generate(yh_l, x)) goto err0; } /* Append an HMAC. */ HMAC_SHA256_Buf(dhmac_l, PCRYPT_DHMAC_LEN, yh_l, CRYPTO_DH_PUBLEN, &yh_l[CRYPTO_DH_PUBLEN]); /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * proto_crypt_mkkeys(K, nonce_l, nonce_r, yh_r, x, nofps, decr, eh_c, eh_s): * Using the protocol secret ${K}, the local and remote nonces ${nonce_l} and * ${nonce_r}, the remote MACed diffie-hellman handshake parameter ${yh_r}, * and the local diffie-hellman secret ${x}, generate the keys ${eh_c} and * ${eh_s}. If ${nofps} is non-zero, we are performing weak handshaking and * y_SC is set to 1 rather than being computed. If ${decr} is non-zero, * "local" == "S" and "remote" == "C"; otherwise the assignments are opposite. */ int proto_crypt_mkkeys(const struct proto_secret * K, const uint8_t nonce_l[PCRYPT_NONCE_LEN], const uint8_t nonce_r[PCRYPT_NONCE_LEN], const uint8_t yh_r[PCRYPT_YH_LEN], const uint8_t x[PCRYPT_X_LEN], int nofps, int decr, struct proto_keys ** eh_c, struct proto_keys ** eh_s) { uint8_t nonce_y[PCRYPT_NONCE_LEN * 2 + CRYPTO_DH_KEYLEN]; uint8_t dk_2[128]; /* Copy in nonces (in the right order). */ memcpy(&nonce_y[0], decr ? nonce_r : nonce_l, PCRYPT_NONCE_LEN); memcpy(&nonce_y[PCRYPT_NONCE_LEN], decr ? nonce_l : nonce_r, PCRYPT_NONCE_LEN); /* Are we bypassing the diffie-hellman computation? */ if (nofps) { /* We sent y_l = 1, so y_SC is also 1. */ memset(&nonce_y[PCRYPT_NONCE_LEN * 2], 0, CRYPTO_DH_KEYLEN - 1); nonce_y[PCRYPT_NONCE_LEN * 2 + CRYPTO_DH_KEYLEN - 1] = 1; } else { /* Perform the diffie-hellman computation. */ if (crypto_dh_compute(yh_r, x, &nonce_y[PCRYPT_NONCE_LEN * 2])) goto err0; } /* Compute dk_2. */ PBKDF2_SHA256(K->K, 32, nonce_y, PCRYPT_NONCE_LEN * 2 + CRYPTO_DH_KEYLEN, 1, dk_2, 128); /* Create key structures. */ if ((*eh_c = mkkeypair(&dk_2[0])) == NULL) goto err0; if ((*eh_s = mkkeypair(&dk_2[64])) == NULL) goto err1; /* Success! */ return (0); err1: proto_crypt_free(*eh_c); err0: /* Failure! */ return (-1); } /** * proto_crypt_enc(ibuf, len, obuf, k): * Encrypt ${len} bytes from ${ibuf} into PCRYPT_ESZ bytes using the keys in * ${k}, and write the result into ${obuf}. */ void proto_crypt_enc(uint8_t * ibuf, size_t len, uint8_t obuf[PCRYPT_ESZ], struct proto_keys * k) { HMAC_SHA256_CTX ctx; uint8_t pnum_exp[8]; /* Sanity-check the length. */ assert(len <= PCRYPT_MAXDSZ); /* Copy the decrypted data into the encrypted buffer. */ memcpy(obuf, ibuf, len); /* Pad up to PCRYPT_MAXDSZ with zeroes. */ memset(&obuf[len], 0, PCRYPT_MAXDSZ - len); /* Add the length. */ be32enc(&obuf[PCRYPT_MAXDSZ], len); /* Encrypt the buffer in-place. */ crypto_aesctr_buf(&k->k_aes, k->pnum, obuf, obuf, PCRYPT_MAXDSZ + 4); /* Append an HMAC. */ be64enc(pnum_exp, k->pnum); HMAC_SHA256_Init(&ctx, k->k_hmac, 32); HMAC_SHA256_Update(&ctx, obuf, PCRYPT_MAXDSZ + 4); HMAC_SHA256_Update(&ctx, pnum_exp, 8); HMAC_SHA256_Final(&obuf[PCRYPT_MAXDSZ + 4], &ctx); /* Increment packet number. */ k->pnum += 1; } /** * proto_crypt_dec(ibuf, obuf, k): * Decrypt PCRYPT_ESZ bytes from ${ibuf} using the keys in ${k}. If the data * is valid, write it into ${obuf} and return the length; otherwise, return * -1. */ ssize_t proto_crypt_dec(uint8_t ibuf[PCRYPT_ESZ], uint8_t * obuf, struct proto_keys * k) { HMAC_SHA256_CTX ctx; uint8_t hbuf[32]; uint8_t pnum_exp[8]; size_t len; /* Verify HMAC. */ be64enc(pnum_exp, k->pnum); HMAC_SHA256_Init(&ctx, k->k_hmac, 32); HMAC_SHA256_Update(&ctx, ibuf, PCRYPT_MAXDSZ + 4); HMAC_SHA256_Update(&ctx, pnum_exp, 8); HMAC_SHA256_Final(hbuf, &ctx); if (crypto_verify_bytes(hbuf, &ibuf[PCRYPT_MAXDSZ + 4], 32)) return (-1); /* Decrypt the buffer in-place. */ crypto_aesctr_buf(&k->k_aes, k->pnum, ibuf, ibuf, PCRYPT_MAXDSZ + 4); /* Increment packet number. */ k->pnum += 1; /* Parse length. */ len = be32dec(&ibuf[PCRYPT_MAXDSZ]); /* Make sure nobody is being evil here... */ if ((len == 0) || (len > PCRYPT_MAXDSZ)) return (-1); /* Copy the bytes into the output buffer. */ memcpy(obuf, ibuf, len); /* Return the decrypted length. */ return (len); } /** * proto_crypt_free(k): * Free the protocol key structure ${k}. */ void proto_crypt_free(struct proto_keys * k) { /* Free the key structure. */ free(k); } spiped-1.3.1/proto/proto_pipe.h000644 001751 001751 00000001375 12132205630 020130 0ustar00cpercivacperciva000000 000000 #ifndef _PROTO_PIPE_H_ #define _PROTO_PIPE_H_ struct proto_keys; /** * proto_pipe(s_in, s_out, decr, k, status, callback, cookie): * Read bytes from ${s_in} and write them to ${s_out}. If ${decr} is non-zero * then use ${k} to decrypt the bytes; otherwise use ${k} to encrypt them. * If EOF is read, set ${status} to 0, and if an error is encountered set * ${status} to -1; in either case, invoke ${callback}(${cookie}). Return a * cookie which can be passed to proto_pipe_cancel. */ void * proto_pipe(int, int, int, struct proto_keys *, int *, int (*)(void *), void *); /** * proto_pipe_cancel(cookie): * Shut down the pipe created by proto_pipe for which ${cookie} was returned. */ void proto_pipe_cancel(void *); #endif /* !_PROTO_PIPE_H_ */ spiped-1.3.1/proto/proto_conn.h000644 001751 001751 00000001712 12132205630 020123 0ustar00cpercivacperciva000000 000000 #ifndef _PROTO_CONN_H_ #define _PROTO_CONN_H_ /* Opaque structures. */ struct proto_secret; struct sock_addr; /** * proto_conn_create(s, sas, decr, nofps, nokeepalive, K, timeo, * callback_dead, cookie): * Create a connection with one end at ${s} and the other end connecting to * the target addresses ${sas}. If ${decr} is 0, encrypt the outgoing data; * if ${decr} is nonzero, decrypt the outgoing data. If ${nofps} is non-zero, * don't use perfect forward secrecy. Enable transport layer keep-alives (if * applicable) on both sockets if and only if ${nokeepalive} is zero. Drop the * connection if the handshake or connecting to the target takes more than * ${timeo} seconds. When the connection is dropped, invoke * ${callback_dead}(${cookie}). Free ${sas} once it is no longer needed. */ int proto_conn_create(int, struct sock_addr **, int, int, int, const struct proto_secret *, double, int (*)(void *), void *); #endif /* !_CONN_H_ */ spiped-1.3.1/proto/proto_crypt.h000644 001751 001751 00000007040 12132205630 020327 0ustar00cpercivacperciva000000 000000 #ifndef _PCRYPT_H_ #define _PCRYPT_H_ #include #include #include "crypto_dh.h" struct proto_keys; struct proto_secret; /* Size of nonce. */ #define PCRYPT_NONCE_LEN 32 /* Size of temporary MAC keys used for Diffie-Hellman parameters. */ #define PCRYPT_DHMAC_LEN 32 /* Size of private Diffie-Hellman value. */ #define PCRYPT_X_LEN CRYPTO_DH_PRIVLEN /* Size of MACed Diffie-Hellman parameter. */ #define PCRYPT_YH_LEN (CRYPTO_DH_PUBLEN + 32) /** * proto_crypt_secret(filename): * Read the key file ${filename} and return a protocol secret structure. */ struct proto_secret * proto_crypt_secret(const char *); /** * proto_crypt_dhmac(K, nonce_l, nonce_r, dhmac_l, dhmac_r, decr): * Using the protocol secret ${K}, and the local and remote nonces ${nonce_l} * and ${nonce_r}, compute the local and remote diffie-hellman parameter MAC * keys ${dhmac_l} and ${dhmac_r}. If ${decr} is non-zero, "local" == "S" * and "remote" == "C"; otherwise the assignments are opposite. */ void proto_crypt_dhmac(const struct proto_secret *, const uint8_t[PCRYPT_NONCE_LEN], const uint8_t[PCRYPT_NONCE_LEN], uint8_t[PCRYPT_DHMAC_LEN], uint8_t[PCRYPT_DHMAC_LEN], int); /** * proto_crypt_dh_validate(yh_r, dhmac_r): * Return non-zero if the value ${yh_r} received from the remote party is not * correctly MACed using the diffie-hellman parameter MAC key ${dhmac_r}, or * if the included y value is >= the diffie-hellman group modulus. */ int proto_crypt_dh_validate(const uint8_t[PCRYPT_YH_LEN], const uint8_t[PCRYPT_DHMAC_LEN]); /** * proto_crypt_dh_generate(yh_l, x, dhmac_l, nofps): * Using the MAC key ${dhmac_l}, generate the MACed diffie-hellman handshake * parameter ${yh_l}. Store the diffie-hellman private value in ${x}. If * ${nofps} is non-zero, skip diffie-hellman generation and use y = 1. */ int proto_crypt_dh_generate(uint8_t[PCRYPT_YH_LEN], uint8_t[PCRYPT_X_LEN], const uint8_t[PCRYPT_DHMAC_LEN], int); /** * proto_crypt_mkkeys(K, nonce_l, nonce_r, yh_r, x, nofps, decr, eh_c, eh_s): * Using the protocol secret ${K}, the local and remote nonces ${nonce_l} and * ${nonce_r}, the remote MACed diffie-hellman handshake parameter ${yh_r}, * and the local diffie-hellman secret ${x}, generate the keys ${eh_c} and * ${eh_s}. If ${nofps} is non-zero, we are performing weak handshaking and * y_SC is set to 1 rather than being computed. If ${decr} is non-zero, * "local" == "S" and "remote" == "C"; otherwise the assignments are opposite. */ int proto_crypt_mkkeys(const struct proto_secret *, const uint8_t[PCRYPT_NONCE_LEN], const uint8_t[PCRYPT_NONCE_LEN], const uint8_t[PCRYPT_YH_LEN], const uint8_t[PCRYPT_X_LEN], int, int, struct proto_keys **, struct proto_keys **); /* Maximum size of an unencrypted packet. */ #define PCRYPT_MAXDSZ 1024 /* Size of an encrypted packet. */ #define PCRYPT_ESZ (PCRYPT_MAXDSZ + 4 /* len */ + 32 /* hmac */) /** * proto_crypt_enc(ibuf, len, obuf, k): * Encrypt ${len} bytes from ${ibuf} into PCRYPT_ESZ bytes using the keys in * ${k}, and write the result into ${obuf}. */ void proto_crypt_enc(uint8_t *, size_t, uint8_t[PCRYPT_ESZ], struct proto_keys *); /** * proto_crypt_dec(ibuf, obuf, k): * Decrypt PCRYPT_ESZ bytes from ${ibuf} using the keys in ${k}. If the data * is valid, write it into ${obuf} and return the length; otherwise, return * -1. */ ssize_t proto_crypt_dec(uint8_t[PCRYPT_ESZ], uint8_t *, struct proto_keys *); /** * proto_crypt_free(k): * Free the protocol key structure ${k}. */ void proto_crypt_free(struct proto_keys *); #endif /* !_PCRYPT_H_ */ spiped-1.3.1/proto/proto_handshake.c000644 001751 001751 00000016775 12132205630 021126 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include "crypto_entropy.h" #include "network.h" #include "proto_crypt.h" #include "proto_handshake.h" struct handshake_cookie { int (* callback)(void *, struct proto_keys *, struct proto_keys *); void * cookie; int s; int decr; int nofps; const struct proto_secret * K; uint8_t nonce_local[PCRYPT_NONCE_LEN]; uint8_t nonce_remote[PCRYPT_NONCE_LEN]; uint8_t dhmac_local[PCRYPT_DHMAC_LEN]; uint8_t dhmac_remote[PCRYPT_DHMAC_LEN]; uint8_t x[PCRYPT_X_LEN]; uint8_t yh_local[PCRYPT_YH_LEN]; uint8_t yh_remote[PCRYPT_YH_LEN]; void * read_cookie; void * write_cookie; }; static int callback_nonce_write(void *, ssize_t); static int callback_nonce_read(void *, ssize_t); static int gotnonces(struct handshake_cookie *); static int dhread(struct handshake_cookie *); static int callback_dh_read(void *, ssize_t); static int dhwrite(struct handshake_cookie *); static int callback_dh_write(void *, ssize_t); static int handshakedone(struct handshake_cookie *); /* The handshake failed. Call back and clean up. */ static int handshakefail(struct handshake_cookie * H) { int rc; /* Cancel any pending network read or write. */ if (H->read_cookie != NULL) network_read_cancel(H->read_cookie); if (H->write_cookie != NULL) network_write_cancel(H->write_cookie); /* Perform the callback. */ rc = (H->callback)(H->cookie, NULL, NULL); /* Free the cookie. */ free(H); /* Return status from callback. */ return (rc); } /** * proto_handshake(s, decr, nofps, K, callback, cookie): * Perform a protocol handshake on socket ${s}. If ${decr} is non-zero we are * at the receiving end of the connection; otherwise at the sending end. If * ${nofps} is non-zero, perform a "weak" handshake without forward perfect * secrecy. The shared protocol secret is ${K}. Upon completion, invoke * ${callback}(${cookie}, f, r) where f contains the keys needed for the * forward direction and r contains the keys needed for the reverse direction; * or w = r = NULL if the handshake failed. Return a cookie which can be * passed to proto_handshake_cancel to cancel the handshake. */ void * proto_handshake(int s, int decr, int nofps, const struct proto_secret * K, int (* callback)(void *, struct proto_keys *, struct proto_keys *), void * cookie) { struct handshake_cookie * H; /* Bake a cookie. */ if ((H = malloc(sizeof(struct handshake_cookie))) == NULL) goto err0; H->callback = callback; H->cookie = cookie; H->s = s; H->decr = decr; H->nofps = nofps; H->K = K; /* Generate a 32-byte connection nonce. */ if (crypto_entropy_read(H->nonce_local, 32)) goto err1; /* Send our nonce. */ if ((H->write_cookie = network_write(s, H->nonce_local, 32, 32, callback_nonce_write, H)) == NULL) goto err1; /* Read the other party's nonce. */ if ((H->read_cookie = network_read(s, H->nonce_remote, 32, 32, callback_nonce_read, H)) == NULL) goto err2; /* Success! */ return (H); err2: network_write_cancel(H->write_cookie); err1: free(H); err0: /* Failure! */ return (NULL); } /* We've written our nonce. */ static int callback_nonce_write(void * cookie, ssize_t len) { struct handshake_cookie * H = cookie; /* This write is no longer pending. */ H->write_cookie = NULL; /* Did we successfully write? */ if (len < 32) return (handshakefail(H)); /* If the nonce read is also done, move on to the next step. */ if (H->read_cookie == NULL) return (gotnonces(H)); /* Nothing to do. */ return (0); } /* We've read a nonce. */ static int callback_nonce_read(void * cookie, ssize_t len) { struct handshake_cookie * H = cookie; /* This read is no longer pending. */ H->read_cookie = NULL; /* Did we successfully read? */ if (len < 32) return (handshakefail(H)); /* If the nonce write is also done, move on to the next step. */ if (H->write_cookie == NULL) return (gotnonces(H)); /* Nothing to do. */ return (0); } /* We have two nonces. Start the DH exchange. */ static int gotnonces(struct handshake_cookie * H) { /* Compute the diffie-hellman parameter MAC keys. */ proto_crypt_dhmac(H->K, H->nonce_local, H->nonce_remote, H->dhmac_local, H->dhmac_remote, H->decr); /* * If we're the server, we need to read the client's diffie-hellman * parameter. If we're the client, we need to generate and send our * diffie-hellman parameter. */ if (H->decr) return (dhread(H)); else return (dhwrite(H)); /* NOTREACHED */ } /* Read a diffie-hellman parameter. */ static int dhread(struct handshake_cookie * H) { /* Read the remote signed diffie-hellman parameter. */ if ((H->read_cookie = network_read(H->s, H->yh_remote, PCRYPT_YH_LEN, PCRYPT_YH_LEN, callback_dh_read, H)) == NULL) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /* We have read a diffie-hellman parameter. */ static int callback_dh_read(void * cookie, ssize_t len) { struct handshake_cookie * H = cookie; /* This read is no longer pending. */ H->read_cookie = NULL; /* Did we successfully read? */ if (len < PCRYPT_YH_LEN) return (handshakefail(H)); /* Is the value we read valid? */ if (proto_crypt_dh_validate(H->yh_remote, H->dhmac_remote)) return (handshakefail(H)); /* * If we're the server, we need to send our diffie-hellman parameter * next. If we're the client, move on to the final computation. */ if (H->decr) return (dhwrite(H)); else return (handshakedone(H)); /* NOTREACHED */ } /* Generate and write a diffie-hellman parameter. */ static int dhwrite(struct handshake_cookie * H) { /* Generate a signed diffie-hellman parameter. */ if (proto_crypt_dh_generate(H->yh_local, H->x, H->dhmac_local, H->nofps)) goto err0; /* Write our signed diffie-hellman parameter. */ if ((H->write_cookie = network_write(H->s, H->yh_local, PCRYPT_YH_LEN, PCRYPT_YH_LEN, callback_dh_write, H)) == NULL) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /* We have written our diffie-hellman parameter. */ static int callback_dh_write(void * cookie, ssize_t len) { struct handshake_cookie * H = cookie; /* This write is no longer pending. */ H->write_cookie = NULL; /* Did we successfully write? */ if (len < PCRYPT_YH_LEN) return (handshakefail(H)); /* * If we're the server, move on to the final computation. If we're * the client, we need to read the server's parameter next. */ if (H->decr) return (handshakedone(H)); else return (dhread(H)); /* NOTREACHED */ } /* We've got all the bits; do the final computation and callback. */ static int handshakedone(struct handshake_cookie * H) { struct proto_keys * c; struct proto_keys * s; int rc; /* Sanity-check: There should be no callbacks in progress. */ assert(H->read_cookie == NULL); assert(H->write_cookie == NULL); /* Perform the final computation. */ if (proto_crypt_mkkeys(H->K, H->nonce_local, H->nonce_remote, H->yh_remote, H->x, H->nofps, H->decr, &c, &s)) goto err0; /* Perform the callback. */ rc = (H->callback)(H->cookie, c, s); /* Free the cookie. */ free(H); /* Return status code from callback. */ return (rc); err0: /* Failure! */ return (-1); } /** * proto_handshake_cancel(cookie): * Cancel the handshake for which proto_handshake returned ${cookie}. */ void proto_handshake_cancel(void * cookie) { struct handshake_cookie * H = cookie; /* Cancel any in-progress network operations. */ if (H->read_cookie != NULL) network_read_cancel(H->read_cookie); if (H->write_cookie != NULL) network_write_cancel(H->write_cookie); /* Free the cookie. */ free(H); } spiped-1.3.1/proto/proto_handshake.h000644 001751 001751 00000002122 12132205630 021110 0ustar00cpercivacperciva000000 000000 #ifndef _PROTO_HANDSHAKE_H_ #define _PROTO_HANDSHAKE_H_ /* Opaque structures. */ struct proto_keys; struct proto_secret; /** * proto_handshake(s, decr, nofps, K, callback, cookie): * Perform a protocol handshake on socket ${s}. If ${decr} is non-zero we are * at the receiving end of the connection; otherwise at the sending end. If * ${nofps} is non-zero, perform a "weak" handshake without forward perfect * secrecy. The shared protocol secret is ${K}. Upon completion, invoke * ${callback}(${cookie}, f, r) where f contains the keys needed for the * forward direction and r contains the keys needed for the reverse direction; * or w = r = NULL if the handshake failed. Return a cookie which can be * passed to proto_handshake_cancel to cancel the handshake. */ void * proto_handshake(int, int, int, const struct proto_secret *, int (*)(void *, struct proto_keys *, struct proto_keys *), void *); /** * proto_handshake_cancel(cookie): * Cancel the handshake for which proto_handshake returned ${cookie}. */ void proto_handshake_cancel(void *); #endif /* !_PROTO_HANDSHAKE_H_ */ spiped-1.3.1/lib/network/000755 001751 001751 00000000000 12132205630 016665 5ustar00cpercivacperciva000000 000000 spiped-1.3.1/lib/dnsthread/000755 001751 001751 00000000000 12132205630 017150 5ustar00cpercivacperciva000000 000000 spiped-1.3.1/lib/util/000755 001751 001751 00000000000 12132205630 016151 5ustar00cpercivacperciva000000 000000 spiped-1.3.1/lib/datastruct/000755 001751 001751 00000000000 12132205630 017352 5ustar00cpercivacperciva000000 000000 spiped-1.3.1/lib/crypto/000755 001751 001751 00000000000 12132205630 016514 5ustar00cpercivacperciva000000 000000 spiped-1.3.1/lib/alg/000755 001751 001751 00000000000 12132205630 015737 5ustar00cpercivacperciva000000 000000 spiped-1.3.1/lib/events/000755 001751 001751 00000000000 12132205630 016500 5ustar00cpercivacperciva000000 000000 spiped-1.3.1/lib/events/events_network.c000644 001751 001751 00000015477 12132205630 021737 0ustar00cpercivacperciva000000 000000 #include #include #include #include "elasticarray.h" #include "warnp.h" #include "events_internal.h" #include "events.h" /* Structure for holding readability and writability events for a socket. */ struct socketrec { struct eventrec * reader; struct eventrec * writer; }; /* List of sockets. */ ELASTICARRAY_DECL(SOCKETLIST, socketlist, struct socketrec); static SOCKETLIST S = NULL; /* File descriptor sets containing unevented ready sockets. */ static fd_set readfds; static fd_set writefds; /* Position to which events_network_get has scanned in *fds. */ static size_t fdscanpos; /* Initialize the socket list if we haven't already done so. */ static int initsocketlist(void) { /* If we're already initialized, do nothing. */ if (S != NULL) goto done; /* Initialize the socket list. */ if ((S = socketlist_init(0)) == NULL) goto err0; /* There are no unevented ready sockets. */ fdscanpos = FD_SETSIZE; done: /* Success! */ return (0); err0: /* Failure! */ return (-1); } /* Grow the socket list and initialize new records. */ static int growsocketlist(size_t nrec) { size_t i; /* Get the old size. */ i = socketlist_getsize(S); /* Grow the list. */ if (socketlist_resize(S, nrec)) goto err0; /* Initialize new members. */ for (; i < nrec; i++) { socketlist_get(S, i)->reader = NULL; socketlist_get(S, i)->writer = NULL; } /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * events_network_register(func, cookie, s, op): * Register ${func}(${cookie}) to be run when socket ${s} is ready for * reading or writing depending on whether ${op} is EVENTS_NETWORK_OP_READ or * EVENTS_NETWORK_OP_WRITE. If there is already an event registration for * this ${s}/${op} pair, errno will be set to EEXIST and the function will * fail. */ int events_network_register(int (*func)(void *), void * cookie, int s, int op) { struct eventrec ** r; /* Initialize if necessary. */ if (initsocketlist()) goto err0; /* Sanity-check socket number. */ if ((s < 0) || (s >= (int)FD_SETSIZE)) { warn0("Invalid file descriptor for network event: %d", s); goto err0; } /* Sanity-check operation. */ if ((op != EVENTS_NETWORK_OP_READ) && (op != EVENTS_NETWORK_OP_WRITE)) { warn0("Invalid operation for network event: %d", op); goto err0; } /* Grow the array if necessary. */ if (((size_t)(s) >= socketlist_getsize(S)) && (growsocketlist(s + 1) != 0)) goto err0; /* Look up the relevant event pointer. */ if (op == EVENTS_NETWORK_OP_READ) r = &socketlist_get(S, s)->reader; else r = &socketlist_get(S, s)->writer; /* Error out if we already have an event registered. */ if (*r != NULL) { errno = EEXIST; goto err0; } /* Register the new event. */ if ((*r = events_mkrec(func, cookie)) == NULL) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * events_network_cancel(s, op): * Cancel the event registered for the socket/operation pair ${s}/${op}. If * there is no such registration, errno will be set to ENOENT and the * function will fail. */ int events_network_cancel(int s, int op) { struct eventrec ** r; /* Initialize if necessary. */ if (initsocketlist()) goto err0; /* Sanity-check socket number. */ if ((s < 0) || (s >= (int)FD_SETSIZE)) { warn0("Invalid file descriptor for network event: %d", s); goto err0; } /* Sanity-check operation. */ if ((op != EVENTS_NETWORK_OP_READ) && (op != EVENTS_NETWORK_OP_WRITE)) { warn0("Invalid operation for network event: %d", op); goto err0; } /* We have no events registered beyond the end of the array. */ if ((size_t)(s) >= socketlist_getsize(S)) { errno = ENOENT; goto err0; } /* Look up the relevant event pointer. */ if (op == EVENTS_NETWORK_OP_READ) r = &socketlist_get(S, s)->reader; else r = &socketlist_get(S, s)->writer; /* Check if we have an event. */ if (*r == NULL) { errno = ENOENT; goto err0; } /* Free the event. */ events_freerec(*r); *r = NULL; /* * Since there is no longer an event registered for this socket / * operation pair, it doesn't make any sense for it to be ready. */ if (op == EVENTS_NETWORK_OP_READ) FD_CLR(s, &readfds); else FD_CLR(s, &writefds); /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * events_network_select(tv): * Check for socket readiness events, waiting up to ${tv} time if there are * no sockets immediately ready, or indefinitely if ${tv} is NULL. */ int events_network_select(struct timeval * tv) { size_t i; /* Initialize if necessary. */ if (initsocketlist()) goto err0; /* Zero the fd sets... */ FD_ZERO(&readfds); FD_ZERO(&writefds); /* ... and add the ones we care about. */ for (i = 0; i < socketlist_getsize(S); i++) { if (socketlist_get(S, i)->reader) FD_SET(i, &readfds); if (socketlist_get(S, i)->writer) FD_SET(i, &writefds); } /* Select. */ while (select(socketlist_getsize(S), &readfds, &writefds, NULL, tv) == -1) { /* EINTR is harmless. */ if (errno == EINTR) continue; /* Anything else is an error. */ warnp("select()"); goto err0; } /* We should start scanning for events at the beginning. */ fdscanpos = 0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * events_network_get(void): * Find a socket readiness event which was identified by a previous call to * events_network_select, and return it as an eventrec structure; or return * NULL if there are no such events available. The caller is responsible for * freeing the returned memory. */ struct eventrec * events_network_get(void) { struct eventrec * r; size_t nfds = socketlist_getsize(S); /* We haven't found any events yet. */ r = NULL; /* Scan through the fd sets looking for ready sockets. */ for (; fdscanpos < nfds; fdscanpos++) { /* Are we ready for reading? */ if (FD_ISSET(fdscanpos, &readfds)) { r = socketlist_get(S, fdscanpos)->reader; socketlist_get(S, fdscanpos)->reader = NULL; FD_CLR(fdscanpos, &readfds); break; } /* Are we ready for writing? */ if (FD_ISSET(fdscanpos, &writefds)) { r = socketlist_get(S, fdscanpos)->writer; socketlist_get(S, fdscanpos)->writer = NULL; FD_CLR(fdscanpos, &writefds); break; } } /* Return the event we found, or NULL if we didn't find any. */ return (r); } /** * events_network_shutdown(void) * Clean up and free memory. This call is not necessary on program exit and * is only expected to be useful when checking for memory leaks. */ void events_network_shutdown(void) { size_t i; /* If we're not initialized, do nothing. */ if (S == NULL) return; /* If we have any registered events, do nothing. */ for (i = 0; i < socketlist_getsize(S); i++) { if ((socketlist_get(S, i)->reader != NULL) || (socketlist_get(S, i)->writer != NULL)) return; } /* Free the socket list. */ socketlist_free(S); S = NULL; } spiped-1.3.1/lib/events/events_immediate.c000644 001751 001751 00000006440 12132205630 022172 0ustar00cpercivacperciva000000 000000 #include #include #include #include "mpool.h" #include "events_internal.h" #include "events.h" struct eventq { struct eventrec * r; struct eventq * next; struct eventq * prev; int prio; }; MPOOL(eventq, struct eventq, 4096); /* First nodes in the linked lists. */ static struct eventq * heads[32] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; /* For non-NULL heads[i], tails[i] is the last node in the list. */ static struct eventq * tails[32]; /* For i < minq, heads[i] == NULL. */ static int minq = 0; /** * events_immediate_register(func, cookie, prio): * Register ${func}(${cookie}) to be run the next time events_run is invoked, * after immediate events with smaller ${prio} values and before events with * larger ${prio} values. The value ${prio} must be in the range [0, 31]. * Return a cookie which can be passed to events_immediate_cancel. */ void * events_immediate_register(int (*func)(void *), void * cookie, int prio) { struct eventrec * r; struct eventq * q; /* Sanity check. */ assert((prio >= 0) && (prio < 32)); /* Bundle into an eventrec record. */ if ((r = events_mkrec(func, cookie)) == NULL) goto err0; /* Create a linked list node. */ if ((q = mpool_eventq_malloc()) == NULL) goto err1; q->r = r; q->next = NULL; q->prev = NULL; q->prio = prio; /* Add to the queue. */ if (heads[prio] == NULL) { heads[prio] = q; if (prio < minq) minq = prio; } else { tails[prio]->next = q; q->prev = tails[prio]; } tails[prio] = q; /* Success! */ return (q); err1: events_freerec(r); err0: /* Failure! */ return (NULL); } /** * events_immediate_cancel(cookie): * Cancel the immediate event for which the cookie ${cookie} was returned by * events_immediate_register. */ void events_immediate_cancel(void * cookie) { struct eventq * q = cookie; int prio = q->prio; /* If we have a predecessor, point it at our successor. */ if (q->prev != NULL) q->prev->next = q->next; else heads[prio] = q->next; /* If we have a successor, point it at our predecessor. */ if (q->next != NULL) q->next->prev = q->prev; else tails[prio] = q->prev; /* Free the eventrec. */ events_freerec(q->r); /* Return the node to the malloc pool. */ mpool_eventq_free(q); } /** * events_immediate_get(void): * Remove and return an eventrec structure from the immediate event queue, * or return NULL if there are no such events. The caller is responsible for * freeing the returned memory. */ struct eventrec * events_immediate_get(void) { struct eventq * q; struct eventrec * r; int prio; /* Scan through priorities until we find an event or run out. */ for (prio = minq; prio < 32; prio++) { /* Did we find an event? */ if (heads[prio] != NULL) break; /* This queue is empty; move on to the next one. */ minq++; } /* Are there any events? */ if (prio == 32) return (NULL); /* Remove the first node from the linked list. */ q = heads[prio]; heads[prio] = q->next; if (heads[prio] != NULL) heads[prio]->prev = NULL; /* Extract the eventrec. */ r = q->r; /* Return the node to the malloc pool. */ mpool_eventq_free(q); /* Return the eventrec. */ return (r); } spiped-1.3.1/lib/events/events_timer.c000644 001751 001751 00000012657 12132205630 021363 0ustar00cpercivacperciva000000 000000 #include #include #include #include "monoclock.h" #include "timerqueue.h" #include "events_internal.h" #include "events.h" struct timerrec { struct eventrec * r; void * cookie; struct timeval tv_orig; }; static struct timerqueue * Q = NULL; /** * events_timer_register(func, cookie, timeo): * Register ${func}(${cookie}) to be run ${timeo} in the future. Return a * cookie which can be passed to events_timer_cancel or events_timer_reset. */ void * events_timer_register(int (*func)(void *), void * cookie, const struct timeval * timeo) { struct eventrec * r; struct timerrec * t; struct timeval tv; /* Create the timer queue if it doesn't exist yet. */ if (Q == NULL) { if ((Q = timerqueue_init()) == NULL) goto err0; } /* Bundle into an eventrec record. */ if ((r = events_mkrec(func, cookie)) == NULL) goto err0; /* Create a timer record. */ if ((t = malloc(sizeof(struct timerrec))) == NULL) goto err1; t->r = r; memcpy(&t->tv_orig, timeo, sizeof(struct timeval)); /* Compute the absolute timeout. */ if (monoclock_get(&tv)) goto err2; tv.tv_sec += t->tv_orig.tv_sec; if ((tv.tv_usec += t->tv_orig.tv_usec) >= 1000000) { tv.tv_usec -= 1000000; tv.tv_sec += 1; } /* Add this to the timer queue. */ if ((t->cookie = timerqueue_add(Q, &tv, t)) == NULL) goto err2; /* Success! */ return (t); err2: free(t); err1: events_freerec(r); err0: /* Failure! */ return (NULL); } /** * events_timer_register_double(func, cookie, timeo): * As events_timer_register, but ${timeo} is a double-precision floating point * value specifying a number of seconds. */ void * events_timer_register_double(int (*func)(void *), void * cookie, double timeo) { struct timeval tv; /* Convert timeo to a struct timeval. */ tv.tv_sec = timeo; tv.tv_usec = (timeo - tv.tv_sec) * 1000000.0; /* Schedule the timeout. */ return (events_timer_register(func, cookie, &tv)); } /** * events_timer_cancel(cookie): * Cancel the timer for which the cookie ${cookie} was returned by * events_timer_register. */ void events_timer_cancel(void * cookie) { struct timerrec * t = cookie; /* Remove from the timer queue. */ timerqueue_delete(Q, t->cookie); /* Free the eventrec and timer records. */ events_freerec(t->r); free(t); } /** * events_timer_reset(cookie): * Reset the timer for which the cookie ${cookie} was returned by * events_timer_register to its initial value. */ int events_timer_reset(void * cookie) { struct timerrec * t = cookie; struct timeval tv; /* Compute the new timeout. */ if (monoclock_get(&tv)) goto err0; tv.tv_sec += t->tv_orig.tv_sec; if ((tv.tv_usec += t->tv_orig.tv_usec) >= 1000000) { tv.tv_usec -= 1000000; tv.tv_sec += 1; } /* Adjust the timer. */ timerqueue_increase(Q, t->cookie, &tv); /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * events_timer_min(timeo): * Return via ${timeo} a pointer to the minimum time which must be waited * before a timer will expire; or to NULL if there are no timers. The caller * is responsible for freeing the returned pointer. */ int events_timer_min(struct timeval ** timeo) { struct timeval tnow; const struct timeval * tv; /* If we have no queue, we have no timers; return NULL. */ if (Q == NULL) { *timeo = NULL; goto done; } /* Get the minimum timer from the queue. */ tv = timerqueue_getmin(Q); /* If there are no timers, return NULL. */ if (tv == NULL) { *timeo = NULL; goto done; } /* Allocate space for holding the returned timeval. */ if ((*timeo = malloc(sizeof(struct timeval))) == NULL) goto err0; /* Get the current time... */ if (monoclock_get(&tnow)) goto err1; /* ... and compare it to the minimum timer. */ if ((tnow.tv_sec > tv->tv_sec) || ((tnow.tv_sec == tv->tv_sec) && (tnow.tv_usec > tv->tv_usec))) { /* The timer has already expired, so return zero. */ (*timeo)->tv_sec = 0; (*timeo)->tv_usec = 0; } else { /* Compute the difference. */ (*timeo)->tv_sec = tv->tv_sec - tnow.tv_sec; (*timeo)->tv_usec = tv->tv_usec - tnow.tv_usec; if (tv->tv_usec < tnow.tv_usec) { (*timeo)->tv_usec += 1000000; (*timeo)->tv_sec -= 1; } } done: /* Success! */ return (0); err1: free(*timeo); err0: /* Failure! */ return (-1); } /** * events_timer_get(r): * Return via ${r} a pointer to an eventrec structure corresponding to an * expired timer, and delete said timer; or to NULL if there are no expired * timers. The caller is responsible for freeing the returned pointer. */ int events_timer_get(struct eventrec ** r) { struct timeval tnow; struct timerrec * t; /* If we have no queue, we have no timers; return NULL. */ if (Q == NULL) { *r = NULL; goto done; } /* Get current time. */ if (monoclock_get(&tnow)) goto err0; /* Get an expired timer, if there is one. */ t = timerqueue_getptr(Q, &tnow); /* If there is an expired timer... */ if (t != NULL) { /* ... pass back the eventrec and free the timer. */ *r = t->r; free(t); } else { /* Otherwise, return NULL. */ *r = NULL; } done: /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * events_timer_shutdown(void): * Clean up and free memory. This call is not necessary on program exit and * is only expected to be useful when checking for memory leaks. */ void events_timer_shutdown(void) { /* If we have a queue and it is empty, free it. */ if ((Q != NULL) && (timerqueue_getmin(Q) == NULL)) { timerqueue_free(Q); Q = NULL; } } spiped-1.3.1/lib/events/events.c000644 001751 001751 00000007703 12132205630 020157 0ustar00cpercivacperciva000000 000000 #include #include #include "mpool.h" #include "events_internal.h" #include "events.h" /* Event structure. */ struct eventrec { int (*func)(void *); void * cookie; }; MPOOL(eventrec, struct eventrec, 4096); /* Zero timeval, for use with non-blocking event runs. */ struct timeval tv_zero = {0, 0}; /** * events_mkrec(func, cookie): * Package ${func}, ${cookie} into a struct eventrec. */ struct eventrec * events_mkrec(int (*func)(void *), void * cookie) { struct eventrec * r; /* Allocate structure. */ if ((r = mpool_eventrec_malloc()) == NULL) goto err0; /* Initialize. */ r->func = func; r->cookie = cookie; /* Success! */ return (r); err0: /* Failure! */ return (NULL); } /** * events_freerec(r): * Free the eventrec ${r}. */ void events_freerec(struct eventrec * r) { mpool_eventrec_free(r); } /* Do an event. This makes events_run cleaner. */ static inline int doevent(struct eventrec * r) { int rc; /* Invoke the callback. */ rc = (r->func)(r->cookie); /* Free the event record. */ mpool_eventrec_free(r); /* Return the status code from the callback. */ return (rc); } /** * events_run(void): * Run events. Events registered via events_immediate_register will be run * first, in order of increasing ${prio} values; then events associated with * ready sockets registered via events_network_register; finally, events * associated with expired timers registered via events_timer_register will * be run. If any event function returns a non-zero result, no further * events will be run and said non-zero result will be returned; on error, * -1 will be returned. */ int events_run(void) { struct eventrec * r; struct timeval * tv; int rc = 0; /* If we have any immediate events, process them and return. */ if ((r = events_immediate_get()) != NULL) { while (r != NULL) { /* Process the event. */ if ((rc = doevent(r)) != 0) goto done; /* Get the next event. */ r = events_immediate_get(); } /* We've processed at least one event; time to return. */ goto done; } /* * Figure out the maximum duration to block, and wait up to that * duration for network events to become available. */ if (events_timer_min(&tv)) goto err0; if (events_network_select(tv)) goto err1; free(tv); /* * Check for available immediate events, network events, and timer * events, in that order of priority; exit only when no more events * are available. */ do { /* Run an immediate event, if one is available. */ if ((r = events_immediate_get()) != NULL) { if ((rc = doevent(r)) != 0) goto done; continue; } /* Run a network event, if one is available. */ if ((r = events_network_get()) != NULL) { if ((rc = doevent(r)) != 0) goto done; continue; } /* Check if any new network events are available. */ if (events_network_select(&tv_zero)) goto err0; if ((r = events_network_get()) != NULL) { if ((rc = doevent(r)) != 0) goto done; continue; } /* Run a timer event, if one is available. */ if (events_timer_get(&r)) goto err0; if (r != NULL) { if ((rc = doevent(r)) != 0) goto done; continue; } /* No events available. */ break; } while (1); done: /* Success! */ return (rc); err1: free(tv); err0: /* Failure! */ return (-1); } /** * events_spin(done): * Run events until ${done} is non-zero (and return 0), an error occurs (and * return -1), or a callback returns a non-zero status (and return the status * code from the callback). */ int events_spin(int * done) { int rc = 0; /* Loop until we're done or have a non-zero status. */ while ((done[0] == 0) && (rc == 0)) { /* Run events. */ rc = events_run(); } /* Return status code. */ return (rc); } /** * events_shutdown(void): * Clean up and free memory. This call is not necessary on program exit and * is only expected to be useful when checking for memory leaks. */ void events_shutdown(void) { events_network_shutdown(); events_timer_shutdown(); } spiped-1.3.1/lib/events/events_internal.h000644 001751 001751 00000004335 12132205630 022056 0ustar00cpercivacperciva000000 000000 #ifndef _EVENTS_INTERNAL_H_ #define _EVENTS_INTERNAL_H_ #include /* Opaque event structure. */ struct eventrec; /** * events_mkrec(func, cookie): * Package ${func}, ${cookie} into a struct eventrec. */ struct eventrec * events_mkrec(int (*)(void *), void *); /** * events_freerec(r): * Free the eventrec ${r}. */ void events_freerec(struct eventrec *); /** * events_immediate_get(void): * Remove and return an eventrec structure from the immediate event queue, * or return NULL if there are no such events. The caller is responsible for * freeing the returned memory. */ struct eventrec * events_immediate_get(void); /** * events_network_select(tv): * Check for socket readiness events, waiting up to ${tv} time if there are * no sockets immediately ready, or indefinitely if ${tv} is NULL. */ int events_network_select(struct timeval *); /** * events_network_get(void): * Find a socket readiness event which was identified by a previous call to * events_network_select, and return it as an eventrec structure; or return * NULL if there are no such events available. The caller is responsible for * freeing the returned memory. */ struct eventrec * events_network_get(void); /** * events_network_shutdown(void) * Clean up and free memory. This call is not necessary on program exit and * is only expected to be useful when checking for memory leaks. */ void events_network_shutdown(void); /** * events_timer_min(timeo): * Return via ${timeo} a pointer to the minimum time which must be waited * before a timer will expire; or to NULL if there are no timers. The caller * is responsible for freeing the returned pointer. */ int events_timer_min(struct timeval **); /** * events_timer_get(r): * Return via ${r} a pointer to an eventrec structure corresponding to an * expired timer, and delete said timer; or to NULL if there are no expired * timers. The caller is responsible for freeing the returned pointer. */ int events_timer_get(struct eventrec **); /** * events_timer_shutdown(void): * Clean up and free memory. This call is not necessary on program exit and * is only expected to be useful when checking for memory leaks. */ void events_timer_shutdown(void); #endif /* !_EVENTS_INTERNAL_H_ */ spiped-1.3.1/lib/events/events.h000644 001751 001751 00000006434 12132205630 020164 0ustar00cpercivacperciva000000 000000 #ifndef _EVENTS_H_ #define _EVENTS_H_ #include /** * events_immediate_register(func, cookie, prio): * Register ${func}(${cookie}) to be run the next time events_run is invoked, * after immediate events with smaller ${prio} values and before events with * larger ${prio} values. The value ${prio} must be in the range [0, 31]. * Return a cookie which can be passed to events_immediate_cancel. */ void * events_immediate_register(int (*)(void *), void *, int); /** * events_immediate_cancel(cookie): * Cancel the immediate event for which the cookie ${cookie} was returned by * events_immediate_register. */ void events_immediate_cancel(void *); /* "op" parameter to events_network_register. */ #define EVENTS_NETWORK_OP_READ 0 #define EVENTS_NETWORK_OP_WRITE 1 /** * events_network_register(func, cookie, s, op): * Register ${func}(${cookie}) to be run when socket ${s} is ready for * reading or writing depending on whether ${op} is EVENTS_NETWORK_OP_READ or * EVENTS_NETWORK_OP_WRITE. If there is already an event registration for * this ${s}/${op} pair, errno will be set to EEXIST and the function will * fail. */ int events_network_register(int (*)(void *), void *, int, int); /** * events_network_cancel(s, op): * Cancel the event registered for the socket/operation pair ${s}/${op}. If * there is no such registration, errno will be set to ENOENT and the * function will fail. */ int events_network_cancel(int, int); /** * events_timer_register(func, cookie, timeo): * Register ${func}(${cookie}) to be run ${timeo} in the future. Return a * cookie which can be passed to events_timer_cancel or events_timer_reset. */ void * events_timer_register(int (*)(void *), void *, const struct timeval *); /** * events_timer_register_double(func, cookie, timeo): * As events_timer_register, but ${timeo} is a double-precision floating point * value specifying a number of seconds. */ void * events_timer_register_double(int (*)(void *), void *, double); /** * events_timer_cancel(cookie): * Cancel the timer for which the cookie ${cookie} was returned by * events_timer_register. */ void events_timer_cancel(void *); /** * events_timer_reset(cookie): * Reset the timer for which the cookie ${cookie} was returned by * events_timer_register to its initial value. */ int events_timer_reset(void *); /** * events_run(void): * Run events. Events registered via events_immediate_register will be run * first, in order of increasing ${prio} values; then events associated with * ready sockets registered via events_network_register; finally, events * associated with expired timers registered via events_timer_register will * be run. If any event function returns a non-zero result, no further * events will be run and said non-zero result will be returned; on error, * -1 will be returned. */ int events_run(void); /** * events_spin(done): * Run events until ${done} is non-zero (and return 0), an error occurs (and * return -1), or a callback returns a non-zero status (and return the status * code from the callback). */ int events_spin(int *); /** * events_shutdown(void): * Clean up and free memory. This call is not necessary on program exit and * is only expected to be useful when checking for memory leaks. */ void events_shutdown(void); #endif /* !_EVENTS_H_ */ spiped-1.3.1/lib/alg/sha256.c000644 001751 001751 00000025014 12132205630 017115 0ustar00cpercivacperciva000000 000000 #include #include #include "sysendian.h" #include "sha256.h" /* * Encode a length len/4 vector of (uint32_t) into a length len vector of * (uint8_t) in big-endian form. Assumes len is a multiple of 4. */ static void be32enc_vect(uint8_t *dst, const uint32_t *src, size_t len) { size_t i; for (i = 0; i < len / 4; i++) be32enc(dst + i * 4, src[i]); } /* * Decode a big-endian length len vector of (uint8_t) into a length * len/4 vector of (uint32_t). Assumes len is a multiple of 4. */ static void be32dec_vect(uint32_t *dst, const uint8_t *src, size_t len) { size_t i; for (i = 0; i < len / 4; i++) dst[i] = be32dec(src + i * 4); } /* Elementary functions used by SHA256 */ #define Ch(x, y, z) ((x & (y ^ z)) ^ z) #define Maj(x, y, z) ((x & (y | z)) | (y & z)) #define SHR(x, n) (x >> n) #define ROTR(x, n) ((x >> n) | (x << (32 - n))) #define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) #define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) #define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) #define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) /* SHA256 round function */ #define RND(a, b, c, d, e, f, g, h, k) \ t0 = h + S1(e) + Ch(e, f, g) + k; \ t1 = S0(a) + Maj(a, b, c); \ d += t0; \ h = t0 + t1; /* Adjusted round function for rotating state */ #define RNDr(S, W, i, k) \ RND(S[(64 - i) % 8], S[(65 - i) % 8], \ S[(66 - i) % 8], S[(67 - i) % 8], \ S[(68 - i) % 8], S[(69 - i) % 8], \ S[(70 - i) % 8], S[(71 - i) % 8], \ W[i] + k) /* * SHA256 block compression function. The 256-bit state is transformed via * the 512-bit input block to produce a new state. */ static void SHA256_Transform(uint32_t * state, const uint8_t block[64]) { uint32_t W[64]; uint32_t S[8]; uint32_t t0, t1; int i; /* 1. Prepare message schedule W. */ be32dec_vect(W, block, 64); for (i = 16; i < 64; i++) W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; /* 2. Initialize working variables. */ memcpy(S, state, 32); /* 3. Mix. */ RNDr(S, W, 0, 0x428a2f98); RNDr(S, W, 1, 0x71374491); RNDr(S, W, 2, 0xb5c0fbcf); RNDr(S, W, 3, 0xe9b5dba5); RNDr(S, W, 4, 0x3956c25b); RNDr(S, W, 5, 0x59f111f1); RNDr(S, W, 6, 0x923f82a4); RNDr(S, W, 7, 0xab1c5ed5); RNDr(S, W, 8, 0xd807aa98); RNDr(S, W, 9, 0x12835b01); RNDr(S, W, 10, 0x243185be); RNDr(S, W, 11, 0x550c7dc3); RNDr(S, W, 12, 0x72be5d74); RNDr(S, W, 13, 0x80deb1fe); RNDr(S, W, 14, 0x9bdc06a7); RNDr(S, W, 15, 0xc19bf174); RNDr(S, W, 16, 0xe49b69c1); RNDr(S, W, 17, 0xefbe4786); RNDr(S, W, 18, 0x0fc19dc6); RNDr(S, W, 19, 0x240ca1cc); RNDr(S, W, 20, 0x2de92c6f); RNDr(S, W, 21, 0x4a7484aa); RNDr(S, W, 22, 0x5cb0a9dc); RNDr(S, W, 23, 0x76f988da); RNDr(S, W, 24, 0x983e5152); RNDr(S, W, 25, 0xa831c66d); RNDr(S, W, 26, 0xb00327c8); RNDr(S, W, 27, 0xbf597fc7); RNDr(S, W, 28, 0xc6e00bf3); RNDr(S, W, 29, 0xd5a79147); RNDr(S, W, 30, 0x06ca6351); RNDr(S, W, 31, 0x14292967); RNDr(S, W, 32, 0x27b70a85); RNDr(S, W, 33, 0x2e1b2138); RNDr(S, W, 34, 0x4d2c6dfc); RNDr(S, W, 35, 0x53380d13); RNDr(S, W, 36, 0x650a7354); RNDr(S, W, 37, 0x766a0abb); RNDr(S, W, 38, 0x81c2c92e); RNDr(S, W, 39, 0x92722c85); RNDr(S, W, 40, 0xa2bfe8a1); RNDr(S, W, 41, 0xa81a664b); RNDr(S, W, 42, 0xc24b8b70); RNDr(S, W, 43, 0xc76c51a3); RNDr(S, W, 44, 0xd192e819); RNDr(S, W, 45, 0xd6990624); RNDr(S, W, 46, 0xf40e3585); RNDr(S, W, 47, 0x106aa070); RNDr(S, W, 48, 0x19a4c116); RNDr(S, W, 49, 0x1e376c08); RNDr(S, W, 50, 0x2748774c); RNDr(S, W, 51, 0x34b0bcb5); RNDr(S, W, 52, 0x391c0cb3); RNDr(S, W, 53, 0x4ed8aa4a); RNDr(S, W, 54, 0x5b9cca4f); RNDr(S, W, 55, 0x682e6ff3); RNDr(S, W, 56, 0x748f82ee); RNDr(S, W, 57, 0x78a5636f); RNDr(S, W, 58, 0x84c87814); RNDr(S, W, 59, 0x8cc70208); RNDr(S, W, 60, 0x90befffa); RNDr(S, W, 61, 0xa4506ceb); RNDr(S, W, 62, 0xbef9a3f7); RNDr(S, W, 63, 0xc67178f2); /* 4. Mix local working variables into global state. */ for (i = 0; i < 8; i++) state[i] += S[i]; /* Clean the stack. */ memset(W, 0, 256); memset(S, 0, 32); t0 = t1 = 0; } static uint8_t PAD[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* Add padding and terminating bit-count. */ static void SHA256_Pad(SHA256_CTX * ctx) { uint8_t len[8]; uint32_t r, plen; /* * Convert length to a vector of bytes -- we do this now rather * than later because the length will change after we pad. */ be32enc_vect(len, ctx->count, 8); /* Add 1--64 bytes so that the resulting length is 56 mod 64. */ r = (ctx->count[1] >> 3) & 0x3f; plen = (r < 56) ? (56 - r) : (120 - r); SHA256_Update(ctx, PAD, (size_t)plen); /* Add the terminating bit-count. */ SHA256_Update(ctx, len, 8); } /** * SHA256_Init(ctx): * Initialize the SHA256 context ${ctx}. */ void SHA256_Init(SHA256_CTX * ctx) { /* Zero bits processed so far. */ ctx->count[0] = ctx->count[1] = 0; /* Magic initialization constants. */ ctx->state[0] = 0x6A09E667; ctx->state[1] = 0xBB67AE85; ctx->state[2] = 0x3C6EF372; ctx->state[3] = 0xA54FF53A; ctx->state[4] = 0x510E527F; ctx->state[5] = 0x9B05688C; ctx->state[6] = 0x1F83D9AB; ctx->state[7] = 0x5BE0CD19; } /** * SHA256_Update(ctx, in, len): * Input ${len} bytes from ${in} into the SHA256 context ${ctx}. */ void SHA256_Update(SHA256_CTX * ctx, const void *in, size_t len) { uint32_t bitlen[2]; uint32_t r; const uint8_t *src = in; /* Return immediately if we have nothing to do. */ if (len == 0) return; /* Number of bytes left in the buffer from previous updates. */ r = (ctx->count[1] >> 3) & 0x3f; /* Convert the length into a number of bits. */ bitlen[1] = ((uint32_t)len) << 3; bitlen[0] = (uint32_t)(len >> 29); /* Update number of bits. */ if ((ctx->count[1] += bitlen[1]) < bitlen[1]) ctx->count[0]++; ctx->count[0] += bitlen[0]; /* Handle the case where we don't need to perform any transforms. */ if (len < 64 - r) { memcpy(&ctx->buf[r], src, len); return; } /* Finish the current block. */ memcpy(&ctx->buf[r], src, 64 - r); SHA256_Transform(ctx->state, ctx->buf); src += 64 - r; len -= 64 - r; /* Perform complete blocks. */ while (len >= 64) { SHA256_Transform(ctx->state, src); src += 64; len -= 64; } /* Copy left over data into buffer. */ memcpy(ctx->buf, src, len); } /** * SHA256_Final(digest, ctx): * Output the SHA256 hash of the data input to the context ${ctx} into the * buffer ${digest}. */ void SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx) { /* Add padding. */ SHA256_Pad(ctx); /* Write the hash. */ be32enc_vect(digest, ctx->state, 32); /* Clear the context state. */ memset((void *)ctx, 0, sizeof(*ctx)); } /** * SHA256_Buf(in, len, digest): * Compute the SHA256 hash of ${len} bytes from $in} and write it to ${digest}. */ void SHA256_Buf(const void * in, size_t len, uint8_t digest[32]) { SHA256_CTX ctx; SHA256_Init(&ctx); SHA256_Update(&ctx, in, len); SHA256_Final(digest, &ctx); } /** * HMAC_SHA256_Init(ctx, K, Klen): * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from * ${K}. */ void HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen) { uint8_t pad[64]; uint8_t khash[32]; const uint8_t * K = _K; size_t i; /* If Klen > 64, the key is really SHA256(K). */ if (Klen > 64) { SHA256_Init(&ctx->ictx); SHA256_Update(&ctx->ictx, K, Klen); SHA256_Final(khash, &ctx->ictx); K = khash; Klen = 32; } /* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */ SHA256_Init(&ctx->ictx); memset(pad, 0x36, 64); for (i = 0; i < Klen; i++) pad[i] ^= K[i]; SHA256_Update(&ctx->ictx, pad, 64); /* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */ SHA256_Init(&ctx->octx); memset(pad, 0x5c, 64); for (i = 0; i < Klen; i++) pad[i] ^= K[i]; SHA256_Update(&ctx->octx, pad, 64); /* Clean the stack. */ memset(khash, 0, 32); memset(pad, 0, 64); } /** * HMAC_SHA256_Update(ctx, in, len): * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}. */ void HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void *in, size_t len) { /* Feed data to the inner SHA256 operation. */ SHA256_Update(&ctx->ictx, in, len); } /** * HMAC_SHA256_Final(digest, ctx): * Output the HMAC-SHA256 of the data input to the context ${ctx} into the * buffer ${digest}. */ void HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx) { uint8_t ihash[32]; /* Finish the inner SHA256 operation. */ SHA256_Final(ihash, &ctx->ictx); /* Feed the inner hash to the outer SHA256 operation. */ SHA256_Update(&ctx->octx, ihash, 32); /* Finish the outer SHA256 operation. */ SHA256_Final(digest, &ctx->octx); /* Clean the stack. */ memset(ihash, 0, 32); } /** * HMAC_SHA256_Buf(K, Klen, in, len, digest): * Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of * length ${Klen}, and write the result to ${digest}. */ void HMAC_SHA256_Buf(const void * K, size_t Klen, const void * in, size_t len, uint8_t digest[32]) { HMAC_SHA256_CTX ctx; HMAC_SHA256_Init(&ctx, K, Klen); HMAC_SHA256_Update(&ctx, in, len); HMAC_SHA256_Final(digest, &ctx); } /** * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). */ void PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen) { HMAC_SHA256_CTX PShctx, hctx; size_t i; uint8_t ivec[4]; uint8_t U[32]; uint8_t T[32]; uint64_t j; int k; size_t clen; /* Compute HMAC state after processing P and S. */ HMAC_SHA256_Init(&PShctx, passwd, passwdlen); HMAC_SHA256_Update(&PShctx, salt, saltlen); /* Iterate through the blocks. */ for (i = 0; i * 32 < dkLen; i++) { /* Generate INT(i + 1). */ be32enc(ivec, (uint32_t)(i + 1)); /* Compute U_1 = PRF(P, S || INT(i)). */ memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX)); HMAC_SHA256_Update(&hctx, ivec, 4); HMAC_SHA256_Final(U, &hctx); /* T_i = U_1 ... */ memcpy(T, U, 32); for (j = 2; j <= c; j++) { /* Compute U_j. */ HMAC_SHA256_Init(&hctx, passwd, passwdlen); HMAC_SHA256_Update(&hctx, U, 32); HMAC_SHA256_Final(U, &hctx); /* ... xor U_j ... */ for (k = 0; k < 32; k++) T[k] ^= U[k]; } /* Copy as many bytes as necessary into buf. */ clen = dkLen - i * 32; if (clen > 32) clen = 32; memcpy(&buf[i * 32], T, clen); } /* Clean PShctx, since we never called _Final on it. */ memset(&PShctx, 0, sizeof(HMAC_SHA256_CTX)); } spiped-1.3.1/lib/alg/sha256.h000644 001751 001751 00000005326 12132205630 017126 0ustar00cpercivacperciva000000 000000 #ifndef _SHA256_H_ #define _SHA256_H_ #include #include /* * Use #defines in order to avoid namespace collisions with anyone else's * SHA256 code (e.g., the code in OpenSSL). */ #define SHA256_Init libcperciva_SHA256_Init #define SHA256_Update libcperciva_SHA256_Update #define SHA256_Final libcperciva_SHA256_Final #define SHA256_Buf libcperciva_SHA256_Buf #define SHA256_CTX libcperciva_SHA256_CTX #define HMAC_SHA256_Init libcperciva_HMAC_SHA256_Init #define HMAC_SHA256_Update libcperciva_HMAC_SHA256_Update #define HMAC_SHA256_Final libcperciva_HMAC_SHA256_Final #define HMAC_SHA256_Buf libcperciva_HMAC_SHA256_Buf #define HMAC_SHA256_CTX libcperciva_HMAC_SHA256_CTX /* Context structure for SHA256 operations. */ typedef struct { uint32_t state[8]; uint32_t count[2]; uint8_t buf[64]; } SHA256_CTX; /** * SHA256_Init(ctx): * Initialize the SHA256 context ${ctx}. */ void SHA256_Init(SHA256_CTX *); /** * SHA256_Update(ctx, in, len): * Input ${len} bytes from ${in} into the SHA256 context ${ctx}. */ void SHA256_Update(SHA256_CTX *, const void *, size_t); /** * SHA256_Final(digest, ctx): * Output the SHA256 hash of the data input to the context ${ctx} into the * buffer ${digest}. */ void SHA256_Final(uint8_t[32], SHA256_CTX *); /** * SHA256_Buf(in, len, digest): * Compute the SHA256 hash of ${len} bytes from $in} and write it to ${digest}. */ void SHA256_Buf(const void *, size_t, uint8_t[32]); /* Context structure for HMAC-SHA256 operations. */ typedef struct { SHA256_CTX ictx; SHA256_CTX octx; } HMAC_SHA256_CTX; /** * HMAC_SHA256_Init(ctx, K, Klen): * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from * ${K}. */ void HMAC_SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t); /** * HMAC_SHA256_Update(ctx, in, len): * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}. */ void HMAC_SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t); /** * HMAC_SHA256_Final(digest, ctx): * Output the HMAC-SHA256 of the data input to the context ${ctx} into the * buffer ${digest}. */ void HMAC_SHA256_Final(uint8_t[32], HMAC_SHA256_CTX *); /** * HMAC_SHA256_Buf(K, Klen, in, len, digest): * Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of * length ${Klen}, and write the result to ${digest}. */ void HMAC_SHA256_Buf(const void *, size_t, const void *, size_t, uint8_t[32]); /** * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen): * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1). */ void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t, uint8_t *, size_t); #endif /* !_SHA256_H_ */ spiped-1.3.1/lib/crypto/crypto_dh.h000644 001751 001751 00000002710 12132205630 020660 0ustar00cpercivacperciva000000 000000 #ifndef _CRYPTO_DH_H_ #define _CRYPTO_DH_H_ #include /* Sizes of Diffie-Hellman private, public, and exchanged keys. */ #define CRYPTO_DH_PRIVLEN 32 #define CRYPTO_DH_PUBLEN 256 #define CRYPTO_DH_KEYLEN 256 /** * crypto_dh_generate_pub(pub, priv): * Compute ${pub} equal to 2^(2^258 + ${priv}) in Diffie-Hellman group #14. */ int crypto_dh_generate_pub(uint8_t[CRYPTO_DH_PUBLEN], const uint8_t[CRYPTO_DH_PRIVLEN]); /** * crypto_dh_generate(pub, priv): * Generate a 256-bit private key ${priv}, and compute ${pub} equal to * 2^(2^258 + ${priv}) mod p where p is the Diffie-Hellman group #14 modulus. * Both values are stored as big-endian integers. */ int crypto_dh_generate(uint8_t[CRYPTO_DH_PUBLEN], uint8_t[CRYPTO_DH_PRIVLEN]); /** * crypto_dh_compute(pub, priv, key): * In the Diffie-Hellman group #14, compute ${pub}^(2^258 + ${priv}) and * write the result into ${key}. All values are big-endian. Note that the * value ${pub} is the public key produced the call to crypto_dh_generate * made by the *other* participant in the key exchange. */ int crypto_dh_compute(const uint8_t[CRYPTO_DH_PUBLEN], const uint8_t[CRYPTO_DH_PRIVLEN], uint8_t[CRYPTO_DH_KEYLEN]); /** * crypto_dh_sanitycheck(pub): * Sanity-check the Diffie-Hellman public value ${pub} by checking that it * is less than the group #14 modulus. Return 0 if sane, -1 if insane. */ int crypto_dh_sanitycheck(const uint8_t[CRYPTO_DH_PUBLEN]); #endif /* !_CRYPTO_DH_H_ */ spiped-1.3.1/lib/crypto/crypto_entropy.c000644 001751 001751 00000011261 12132205630 021761 0ustar00cpercivacperciva000000 000000 #include #include #include #include "entropy.h" #include "sha256.h" #include "crypto_entropy.h" /** * This system implements the HMAC_DRBG pseudo-random number generator as * specified in section 10.1.2 of the NIST SP 800-90 standard. In this * implementation, the optional personalization_string and additional_input * specified in the standard are not implemented. */ /* Internal HMAC_DRBG state. */ static struct { uint8_t Key[32]; uint8_t V[32]; uint32_t reseed_counter; } drbg; /* Set to non-zero once the PRNG has been instantiated. */ static int instantiated = 0; /* Could be as high as 2^48 if we wanted... */ #define RESEED_INTERVAL 256 /* Limited to 2^16 by specification. */ #define GENERATE_MAXLEN 65536 static int instantiate(void); static void update(uint8_t *, size_t); static int reseed(void); static void generate(uint8_t *, size_t); /** * instantiate(void): * Initialize the DRBG state. (Section 10.1.2.3) */ static int instantiate(void) { uint8_t seed_material[48]; /* Obtain random seed_material = (entropy_input || nonce). */ if (entropy_read(seed_material, 48)) return (-1); /* Initialize Key, V, and reseed_counter. */ memset(drbg.Key, 0x00, 32); memset(drbg.V, 0x01, 32); drbg.reseed_counter = 1; /* Mix the random seed into the state. */ update(seed_material, 48); /* Clean the stack. */ memset(seed_material, 0, 48); /* Success! */ return (0); } /** * update(data, datalen): * Update the DRBG state using the provided data. (Section 10.1.2.2) */ static void update(uint8_t * data, size_t datalen) { HMAC_SHA256_CTX ctx; uint8_t K[32]; uint8_t Vx[33]; /* Load (Key, V) into (K, Vx). */ memcpy(K, drbg.Key, 32); memcpy(Vx, drbg.V, 32); /* K <- HMAC(K, V || 0x00 || data). */ Vx[32] = 0x00; HMAC_SHA256_Init(&ctx, K, 32); HMAC_SHA256_Update(&ctx, Vx, 33); HMAC_SHA256_Update(&ctx, data, datalen); HMAC_SHA256_Final(K, &ctx); /* V <- HMAC(K, V). */ HMAC_SHA256_Buf(K, 32, Vx, 32, Vx); /* If the provided data is non-Null, perform another mixing stage. */ if (datalen != 0) { /* K <- HMAC(K, V || 0x01 || data). */ Vx[32] = 0x01; HMAC_SHA256_Init(&ctx, K, 32); HMAC_SHA256_Update(&ctx, Vx, 33); HMAC_SHA256_Update(&ctx, data, datalen); HMAC_SHA256_Final(K, &ctx); /* V <- HMAC(K, V). */ HMAC_SHA256_Buf(K, 32, Vx, 32, Vx); } /* Copy (K, Vx) back to (Key, V). */ memcpy(drbg.Key, K, 32); memcpy(drbg.V, Vx, 32); /* Clean the stack. */ memset(K, 0, 32); memset(Vx, 0, 33); } /** * reseed(void): * Reseed the DRBG state (mix in new entropy). (Section 10.1.2.4) */ static int reseed(void) { uint8_t seed_material[32]; /* Obtain random seed_material = entropy_input. */ if (entropy_read(seed_material, 32)) return (-1); /* Mix the random seed into the state. */ update(seed_material, 32); /* Reset the reseed_counter. */ drbg.reseed_counter = 1; /* Clean the stack. */ memset(seed_material, 0, 32); /* Success! */ return (0); } /** * generate(buf, buflen): * Fill the provided buffer with random bits, assuming that reseed_counter * is less than RESEED_INTERVAL (the caller is responsible for calling * reseed() as needed) and ${buflen} is less than 2^16 (the caller is * responsible for splitting up larger requests). (Section 10.1.2.5) */ static void generate(uint8_t * buf, size_t buflen) { size_t bufpos; assert(buflen <= GENERATE_MAXLEN); assert(drbg.reseed_counter <= RESEED_INTERVAL); /* Iterate until we've filled the buffer. */ for (bufpos = 0; bufpos < buflen; bufpos += 32) { HMAC_SHA256_Buf(drbg.Key, 32, drbg.V, 32, drbg.V); if (buflen - bufpos >= 32) memcpy(&buf[bufpos], drbg.V, 32); else memcpy(&buf[bufpos], drbg.V, buflen - bufpos); } /* Mix up state. */ update(NULL, 0); /* We're one data-generation step closer to needing a reseed. */ drbg.reseed_counter += 1; } /** * crypto_entropy_read(buf, buflen): * Fill the buffer with unpredictable bits. */ int crypto_entropy_read(uint8_t * buf, size_t buflen) { size_t bytes_to_provide; /* Instantiate if needed. */ if (instantiated == 0) { /* Try to instantiate the PRNG. */ if (instantiate()) return (-1); /* We have instantiated the PRNG. */ instantiated = 1; } /* Loop until we've filled the buffer. */ while (buflen > 0) { /* Do we need to reseed? */ if (drbg.reseed_counter > RESEED_INTERVAL) { if (reseed()) return (-1); } /* How much data are we generating in this step? */ if (buflen > GENERATE_MAXLEN) bytes_to_provide = GENERATE_MAXLEN; else bytes_to_provide = buflen; /* Generate bytes. */ generate(buf, bytes_to_provide); /* We've done part of the buffer. */ buf += bytes_to_provide; buflen -= bytes_to_provide; } /* Success! */ return (0); } spiped-1.3.1/lib/crypto/crypto_aesctr.c000644 001751 001751 00000005341 12132205630 021544 0ustar00cpercivacperciva000000 000000 #include #include #include #include "sysendian.h" #include "crypto_aesctr.h" struct crypto_aesctr { const AES_KEY * key; uint64_t nonce; uint64_t bytectr; uint8_t buf[16]; }; /** * crypto_aesctr_init(key, nonce): * Prepare to encrypt/decrypt data with AES in CTR mode, using the provided * expanded key and nonce. The key provided must remain valid for the * lifetime of the stream. */ struct crypto_aesctr * crypto_aesctr_init(const AES_KEY * key, uint64_t nonce) { struct crypto_aesctr * stream; /* Allocate memory. */ if ((stream = malloc(sizeof(struct crypto_aesctr))) == NULL) goto err0; /* Initialize values. */ stream->key = key; stream->nonce = nonce; stream->bytectr = 0; /* Success! */ return (stream); err0: /* Failure! */ return (NULL); } /** * crypto_aesctr_stream(stream, inbuf, outbuf, buflen): * Generate the next ${buflen} bytes of the AES-CTR stream and xor them with * bytes from ${inbuf}, writing the result into ${outbuf}. If the buffers * ${inbuf} and ${outbuf} overlap, they must be identical. */ void crypto_aesctr_stream(struct crypto_aesctr * stream, const uint8_t * inbuf, uint8_t * outbuf, size_t buflen) { uint8_t pblk[16]; size_t pos; int bytemod; for (pos = 0; pos < buflen; pos++) { /* How far through the buffer are we? */ bytemod = stream->bytectr % 16; /* Generate a block of cipherstream if needed. */ if (bytemod == 0) { be64enc(pblk, stream->nonce); be64enc(pblk + 8, stream->bytectr / 16); AES_encrypt(pblk, stream->buf, stream->key); } /* Encrypt a byte. */ outbuf[pos] = inbuf[pos] ^ stream->buf[bytemod]; /* Move to the next byte of cipherstream. */ stream->bytectr += 1; } } /** * crypto_aesctr_free(stream): * Free the provided stream object. */ void crypto_aesctr_free(struct crypto_aesctr * stream) { int i; /* Be compatible with free(NULL). */ if (stream == NULL) return; /* Zero potentially sensitive information. */ for (i = 0; i < 16; i++) stream->buf[i] = 0; stream->bytectr = stream->nonce = 0; /* Free the stream. */ free(stream); } /** * crypto_aesctr_buf(key, nonce, inbuf, outbuf, buflen): * Equivalent to init(key, nonce); stream(inbuf, outbuf, buflen); free. */ void crypto_aesctr_buf(const AES_KEY * key, uint64_t nonce, const uint8_t * inbuf, uint8_t * outbuf, size_t buflen) { struct crypto_aesctr stream_rec; struct crypto_aesctr * stream = &stream_rec; int i; /* Initialize values. */ stream->key = key; stream->nonce = nonce; stream->bytectr = 0; /* Perform the encryption. */ crypto_aesctr_stream(stream, inbuf, outbuf, buflen); /* Zero potentially sensitive information. */ for (i = 0; i < 16; i++) stream->buf[i] = 0; stream->bytectr = stream->nonce = 0; } spiped-1.3.1/lib/crypto/crypto_dh_group14.h000644 001751 001751 00000000312 12132205630 022235 0ustar00cpercivacperciva000000 000000 #ifndef _CRYPTO_DH_GROUP14_H_ #define _CRYPTO_DH_GROUP14_H_ #include /* Diffie-Hellman group #14, from RFC 3526. */ extern uint8_t crypto_dh_group14[]; #endif /* !_CRYPTO_DH_GROUP14_H_ */ spiped-1.3.1/lib/crypto/crypto_entropy.h000644 001751 001751 00000000467 12132205630 021774 0ustar00cpercivacperciva000000 000000 #ifndef _CRYPTO_ENTROPY_H_ #define _CRYPTO_ENTROPY_H_ #include #include /** * crypto_entropy_read(buf, buflen): * Fill the buffer with unpredictable bits. The value ${buflen} must be * less than 2^16. */ int crypto_entropy_read(uint8_t *, size_t); #endif /* !_CRYPTO_ENTROPY_H_ */ spiped-1.3.1/lib/crypto/crypto_aesctr.h000644 001751 001751 00000002211 12132205630 021542 0ustar00cpercivacperciva000000 000000 #ifndef _CRYPTO_AESCTR_H_ #define _CRYPTO_AESCTR_H_ #include #include #include /** * crypto_aesctr_init(key, nonce): * Prepare to encrypt/decrypt data with AES in CTR mode, using the provided * expanded key and nonce. The key provided must remain valid for the * lifetime of the stream. */ struct crypto_aesctr * crypto_aesctr_init(const AES_KEY *, uint64_t); /** * crypto_aesctr_stream(stream, inbuf, outbuf, buflen): * Generate the next ${buflen} bytes of the AES-CTR stream and xor them with * bytes from ${inbuf}, writing the result into ${outbuf}. If the buffers * ${inbuf} and ${outbuf} overlap, they must be identical. */ void crypto_aesctr_stream(struct crypto_aesctr *, const uint8_t *, uint8_t *, size_t); /** * crypto_aesctr_free(stream): * Free the provided stream object. */ void crypto_aesctr_free(struct crypto_aesctr *); /** * crypto_aesctr_buf(key, nonce, inbuf, outbuf, buflen): * Equivalent to init(key, nonce); stream(inbuf, outbuf, buflen); free. */ void crypto_aesctr_buf(const AES_KEY *, uint64_t, const uint8_t *, uint8_t *, size_t); #endif /* !_CRYPTO_AESCTR_H_ */ spiped-1.3.1/lib/crypto/crypto_verify_bytes.c000644 001751 001751 00000000715 12132205630 022775 0ustar00cpercivacperciva000000 000000 #include #include #include "crypto_verify_bytes.h" /** * crypto_verify_bytes(buf0, buf1, len): * Return zero if and only if buf0[0 .. len - 1] and buf1[0 .. len - 1] are * identical. Do not leak any information via timing side channels. */ uint8_t crypto_verify_bytes(const uint8_t * buf0, const uint8_t * buf1, size_t len) { uint8_t rc = 0; size_t i; for (i = 0; i < len; i++) rc = rc | (buf0[i] ^ buf1[i]); return (rc); } spiped-1.3.1/lib/crypto/crypto_dh.c000644 001751 001751 00000015362 12132205630 020662 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include "warnp.h" #include "crypto_entropy.h" #include "crypto_dh_group14.h" #include "crypto_dh.h" static int blinded_modexp(uint8_t r[CRYPTO_DH_PUBLEN], BIGNUM * a, const uint8_t priv[CRYPTO_DH_PRIVLEN]); /* Big-endian representation of 2^256. */ static uint8_t two_exp_256[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /** * blinded_modexp(r, a, priv): * Compute ${r} = ${a}^(2^258 + ${priv}), where ${r} and ${priv} are treated * as big-endian integers; and avoid leaking timing data in this process. */ static int blinded_modexp(uint8_t r[CRYPTO_DH_PUBLEN], BIGNUM * a, const uint8_t priv[CRYPTO_DH_PRIVLEN]) { BIGNUM * two_exp_256_bn; BIGNUM * priv_bn; uint8_t blinding[CRYPTO_DH_PRIVLEN]; BIGNUM * blinding_bn; BIGNUM * priv_blinded; BIGNUM * m_bn; BN_CTX * ctx; BIGNUM * r1; BIGNUM * r2; size_t rlen; /* Construct 2^256 in BN representation. */ if ((two_exp_256_bn = BN_bin2bn(two_exp_256, 33, NULL)) == NULL) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err0; } /* Construct 2^258 + ${priv} in BN representation. */ if ((priv_bn = BN_bin2bn(priv, CRYPTO_DH_PRIVLEN, NULL)) == NULL) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err1; } if ((!BN_add(priv_bn, priv_bn, two_exp_256_bn)) || (!BN_add(priv_bn, priv_bn, two_exp_256_bn)) || (!BN_add(priv_bn, priv_bn, two_exp_256_bn)) || (!BN_add(priv_bn, priv_bn, two_exp_256_bn))) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err2; } /* Generate blinding exponent. */ if (crypto_entropy_read(blinding, CRYPTO_DH_PRIVLEN)) goto err2; if ((blinding_bn = BN_bin2bn(blinding, CRYPTO_DH_PRIVLEN, NULL)) == NULL) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err2; } if (!BN_add(blinding_bn, blinding_bn, two_exp_256_bn)) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err3; } /* Generate blinded exponent. */ if ((priv_blinded = BN_new()) == NULL) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err3; } if (!BN_sub(priv_blinded, priv_bn, blinding_bn)) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err4; } /* Construct group #14 modulus in BN representation. */ if ((m_bn = BN_bin2bn(crypto_dh_group14, 256, NULL)) == NULL) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err4; } /* Allocate BN context. */ if ((ctx = BN_CTX_new()) == NULL) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err5; } /* Allocate space for storing results of exponentiations. */ if ((r1 = BN_new()) == NULL) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err6; } if ((r2 = BN_new()) == NULL) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err7; } /* Perform modular exponentiations. */ if (!BN_mod_exp(r1, a, blinding_bn, m_bn, ctx)) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err8; } if (!BN_mod_exp(r2, a, priv_blinded, m_bn, ctx)) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err8; } /* Compute final result and export to big-endian integer format. */ if (!BN_mod_mul(r1, r1, r2, m_bn, ctx)) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err8; } rlen = BN_num_bytes(r1); if (rlen > CRYPTO_DH_PUBLEN) { warn0("Exponent result too large!"); goto err8; } memset(r, 0, CRYPTO_DH_PUBLEN - rlen); BN_bn2bin(r1, r + CRYPTO_DH_PUBLEN - rlen); /* Free space allocated by BN_new. */ BN_free(r2); BN_free(r1); /* Free context allocated by BN_CTX_new. */ BN_CTX_free(ctx); /* Free space allocated by BN_bin2bn. */ BN_free(m_bn); /* Free space allocated by BN_new. */ BN_free(priv_blinded); /* Free space allocated by BN_bin2bn. */ BN_free(blinding_bn); BN_free(priv_bn); BN_free(two_exp_256_bn); /* Success! */ return (0); err8: BN_free(r2); err7: BN_free(r1); err6: BN_CTX_free(ctx); err5: BN_free(m_bn); err4: BN_free(priv_blinded); err3: BN_free(blinding_bn); err2: BN_free(priv_bn); err1: BN_free(two_exp_256_bn); err0: /* Failure! */ return (-1); } /** * crypto_dh_generate_pub(pub, priv): * Compute ${pub} equal to 2^(2^258 + ${priv}) in Diffie-Hellman group #14. */ int crypto_dh_generate_pub(uint8_t pub[CRYPTO_DH_PUBLEN], const uint8_t priv[CRYPTO_DH_PRIVLEN]) { BIGNUM * two; /* Generate BN representation for 2. */ if ((two = BN_new()) == NULL) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err0; } if (!BN_set_word(two, 2)) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err1; } /* Compute pub = two^(2^258 + priv). */ if (blinded_modexp(pub, two, priv)) goto err1; /* Free storage allocated by BN_new. */ BN_free(two); /* Success! */ return (0); err1: BN_free(two); err0: /* Failure! */ return (-1); } /** * crypto_dh_generate(pub, priv): * Generate a 256-bit private key ${priv}, and compute ${pub} equal to * 2^(2^258 + ${priv}) mod p where p is the Diffie-Hellman group #14 modulus. * Both values are stored as big-endian integers. */ int crypto_dh_generate(uint8_t pub[CRYPTO_DH_PUBLEN], uint8_t priv[CRYPTO_DH_PRIVLEN]) { /* Generate a random private key. */ if (crypto_entropy_read(priv, CRYPTO_DH_PRIVLEN)) goto err0; /* Compute the public key. */ if (crypto_dh_generate_pub(pub, priv)) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * crypto_dh_compute(pub, priv, key): * In the Diffie-Hellman group #14, compute ${pub}^(2^258 + ${priv}) and * write the result into ${key}. All values are big-endian. Note that the * value ${pub} is the public key produced the call to crypto_dh_generate * made by the *other* participant in the key exchange. */ int crypto_dh_compute(const uint8_t pub[CRYPTO_DH_PUBLEN], const uint8_t priv[CRYPTO_DH_PRIVLEN], uint8_t key[CRYPTO_DH_KEYLEN]) { BIGNUM * a; /* Convert ${pub} into BN representation. */ if ((a = BN_bin2bn(pub, CRYPTO_DH_PUBLEN, NULL)) == NULL) { warn0("%s", ERR_error_string(ERR_get_error(), NULL)); goto err0; } /* Compute key = pub^(2^258 + priv). */ if (blinded_modexp(key, a, priv)) goto err1; /* Free storage allocated by BN_bin2bn. */ BN_free(a); /* Success! */ return (0); err1: BN_free(a); err0: /* Failure! */ return (-1); } /** * crypto_dh_sanitycheck(pub): * Sanity-check the Diffie-Hellman public value ${pub} by checking that it * is less than the group #14 modulus. Return 0 if sane, -1 if insane. */ int crypto_dh_sanitycheck(const uint8_t pub[CRYPTO_DH_PUBLEN]) { if (memcmp(pub, crypto_dh_group14, 256) >= 0) return (-1); /* Value is sane. */ return (0); } spiped-1.3.1/lib/crypto/crypto_dh_group14.c000644 001751 001751 00000003745 12132205630 022245 0ustar00cpercivacperciva000000 000000 #include #include "crypto_dh_group14.h" /** * This is the big-endian representation of * p = 2^2048 - 2^1984 + 2^64 * floor(2^1918 pi + 124476) - 1 * where the value 124476 is chosen to be the least positive integer such * that both p and (p - 1)/2 are prime. Diffie-Hellman operations are done * in the group of quadratic residues modulo p, and the integer 2 is a * generator of this group. */ uint8_t crypto_dh_group14[256] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05, 0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f, 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb, 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04, 0xf1, 0x74, 0x6c, 0x08, 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b, 0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, 0xec, 0x07, 0xa2, 0x8f, 0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7c, 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10, 0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xac, 0xaa, 0x68, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; spiped-1.3.1/lib/crypto/crypto_verify_bytes.h000644 001751 001751 00000000632 12132205630 023000 0ustar00cpercivacperciva000000 000000 #ifndef _CRYPTO_VERIFY_BYTES_H_ #define _CRYPTO_VERIFY_BYTES_H_ #include #include /** * crypto_verify_bytes(buf0, buf1, len): * Return zero if and only if buf0[0 .. len - 1] and buf1[0 .. len - 1] are * identical. Do not leak any information via timing side channels. */ uint8_t crypto_verify_bytes(const uint8_t *, const uint8_t *, size_t); #endif /* !_CRYPTO_VERIFY_BYTES_H_ */ spiped-1.3.1/lib/datastruct/ptrheap.h000644 001751 001751 00000005504 12132205630 021172 0ustar00cpercivacperciva000000 000000 #ifndef _PTRHEAP_H_ #define _PTRHEAP_H_ #include /** * Pointer-heap data structure. Arbitrary pointers can be inserted and are * compared using a provided callback; the usual heapy getmin / increasemin / * deletemin algorithms are supported. In addition, a setreccookie callback * can also be provided, in which case the most recent cookie provided for a * heap element can be used to delete or increase that element. Functions * return NULL or (int)(-1) on error and set errno; other return types * indicate that failure is not possible. On error, the heap will be * unmodified. */ /* Opaque pointer-heap type. */ struct ptrheap; /** * ptrheap_init(compar, setreccookie, cookie): * Create and return an empty heap. The function ${compar}(${cookie}, x, y) * should return less than, equal to, or greater than 0 depending on whether * x is less than, equal to, or greater than y; and if ${setreccookie} is * non-zero it will be called as ${setreccookie}(${cookie}, ${ptr}, ${rc}) to * indicate that the value ${rc} is the current record cookie for the pointer * ${ptr}. The function ${setreccookie} may not make any ptrheap_* calls. */ struct ptrheap * ptrheap_init(int (*)(void *, const void *, const void *), void (*)(void *, void *, size_t), void *); /** * ptrheap_create(compar, setreccookie, cookie, N, ptrs): * Create and return a heap, as in ptrheap_init, but with the ${N} pointers * in ${ptrs} as heap elements. This is faster than creating an empty heap * and adding the elements individually. */ struct ptrheap * ptrheap_create(int (*)(void *, const void *, const void *), void (*)(void *, void *, size_t), void *, size_t, void **); /** * ptrheap_add(H, ptr): * Add the pointer ${ptr} to the heap ${H}. */ int ptrheap_add(struct ptrheap *, void *); /** * ptrheap_getmin(H): * Return the minimum pointer in the heap ${H}. If the heap is empty, NULL * is returned. */ void * ptrheap_getmin(struct ptrheap *); /** * ptrheap_delete(H, rc): * Delete from the heap ${H} the element ptr for which the function call * setreccookie(cookie, ptr, ${rc}) was most recently made. */ void ptrheap_delete(struct ptrheap *, size_t); /** * ptrheap_deletemin(H): * Delete the minimum element in the heap ${H}. */ void ptrheap_deletemin(struct ptrheap *); /** * ptrheap_increase(H, rc): * Adjust the heap ${H} to account for the fact that the element ptr for * which the function call setreccookie(cookie, ptr, ${rc}) was most recently * made has incrased. */ void ptrheap_increase(struct ptrheap *, size_t); /** * ptrheap_increasemin(H): * Adjust the heap ${H} to account for the fact that the (formerly) minimum * element has increased. */ void ptrheap_increasemin(struct ptrheap *); /** * ptrheap_free(H): * Free the pointer heap ${H}. */ void ptrheap_free(struct ptrheap *); #endif /* !_PTRHEAP_H_ */ spiped-1.3.1/lib/datastruct/elasticarray.h000644 001751 001751 00000012265 12132205630 022214 0ustar00cpercivacperciva000000 000000 #ifndef _ELASTICARRAY_H_ #define _ELASTICARRAY_H_ #include /** * Elastic Arrays are dynamically resizing arrays which remain within a * factor of 4 of the optimal size for the data they contain and have (within * a constant factor) amortized optimal running time providing that all of * the allocated space is accessed at some point. Functions return NULL or * (int)(-1) on error and set errno; other return types indicate that failure * is not possible. On error, the array will be unmodified. * * The ELASTICARRAY_DECL(type, prefix, rectype) macro can be used to create a * more friendly interface, at the expense of restricting the array to only * holding a single data type. */ /* Opaque elastic array type. */ struct elasticarray; /** * elasticarray_init(nrec, reclen): * Create and return an elastic array holding ${nrec} (uninitialized) records * of length ${reclen}. Takes O(nrec * reclen) time. */ struct elasticarray * elasticarray_init(size_t, size_t); /** * elasticarray_resize(EA, nrec, reclen): * Resize the elastic array pointed to by ${EA} to hold ${nrec} records of * length ${reclen}. If ${nrec} exceeds the number of records previously * held by the array, the additional records will be uninitialized. Takes * O(nrec * reclen) time. */ int elasticarray_resize(struct elasticarray *, size_t, size_t); /** * elasticarray_getsize(EA, reclen): * Return the number of length-${reclen} records in the array, rounding down * if there is a partial record (which can only occur if elasticarray_* * functions have been called with different values of reclen). The value * ${reclen} must be positive. */ size_t elasticarray_getsize(struct elasticarray *, size_t); /** * elasticarray_append(EA, buf, nrec, reclen): * Append to the elastic array ${EA} the ${nrec} records of length ${reclen} * stored in ${buf}. Takes O(nrec * reclen) amortized time. */ int elasticarray_append(struct elasticarray *, const void *, size_t, size_t); /** * elasticarray_shrink(EA, nrec, reclen): * Delete the final ${nrec} records of length ${reclen} from the elastic * array ${EA}. If there are fewer than ${nrec} records, all records * present will be deleted. * * As an exception to the normal rule, an elastic array may occupy more than * 4 times the optimal storage immediately following an elasticarray_shrink * call; but only if realloc(3) failed to shrink a memory allocation. */ void elasticarray_shrink(struct elasticarray *, size_t, size_t); /** * elasticarray_truncate(EA): * Release any spare space in the elastic array ${EA}. */ int elasticarray_truncate(struct elasticarray *); /** * elasticarray_get(EA, pos, reclen): * Return a pointer to record number ${pos} of length ${reclen} in the * elastic array ${EA}. Takes O(1) time. */ void * elasticarray_get(struct elasticarray *, size_t, size_t); /** * elasticarray_free(EA): * Free the elastic array ${EA}. Takes O(1) time. */ void elasticarray_free(struct elasticarray *); /** * ELASTICARRAY_DECL(type, prefix, rectype): * Declare the type ${type} and the following functions: * ${type} ${prefix}_init(size_t nrec); * int ${prefix}_resize(${type} EA, size_t nrec); * size_t ${prefix}_getsize(${type} EA); * int ${prefix}_append(${type} EA, const void * buf, size_t nrec); * void ${prefix}_shrink(${type} EA, size_t nrec); * int ${prefix}_truncate(${type} EA); * ${rectype} * ${prefix}_get(${type} EA, size_t pos); * void ${prefix}_free(${type} EA); */ #define ELASTICARRAY_DECL(type, prefix, rectype) \ static inline struct prefix##_struct * \ prefix##_init(size_t nrec) \ { \ struct elasticarray * EA; \ \ EA = elasticarray_init(nrec, sizeof(rectype)); \ return ((struct prefix##_struct *)EA); \ } \ static inline int \ prefix##_resize(struct prefix##_struct * EA, size_t nrec) \ { \ return (elasticarray_resize((struct elasticarray *)EA, \ nrec, sizeof(rectype))); \ } \ static inline size_t \ prefix##_getsize(struct prefix##_struct * EA) \ { \ return (elasticarray_getsize((struct elasticarray *)EA, \ sizeof(rectype))); \ } \ static inline int \ prefix##_append(struct prefix##_struct * EA, \ rectype const * buf, size_t nrec) \ { \ return (elasticarray_append((struct elasticarray *)EA, \ buf, nrec, sizeof(rectype))); \ } \ static inline void \ prefix##_shrink(struct prefix##_struct * EA, size_t nrec) \ { \ elasticarray_shrink((struct elasticarray *)EA, \ nrec, sizeof(rectype)); \ } \ static inline int \ prefix##_truncate(struct prefix##_struct * EA) \ { \ return (elasticarray_truncate( \ (struct elasticarray *)EA)); \ } \ static inline rectype * \ prefix##_get(struct prefix##_struct * EA, size_t pos) \ { \ rectype * rec; \ \ rec = elasticarray_get((struct elasticarray *)EA, \ pos, sizeof(rectype)); \ return (rec); \ } \ static inline void \ prefix##_free(struct prefix##_struct * EA) \ { \ elasticarray_free((struct elasticarray *)EA); \ } \ typedef struct prefix##_struct * type #endif /* !_ELASTICARRAY_H_ */ spiped-1.3.1/lib/datastruct/timerqueue.h000644 001751 001751 00000003333 12132205630 021712 0ustar00cpercivacperciva000000 000000 #ifndef _TIMERQUEUE_H_ #define _TIMERQUEUE_H_ #include /* Timer priority queue. Contains (timeval, ptr) pairs. */ /* Opaque timer priority queue type. */ struct timerqueue; /** * timerqueue_init(void): * Create and return an empty timer priority queue. */ struct timerqueue * timerqueue_init(void); /** * timerqueue_add(Q, tv, ptr): * Add the pair (${tv}, ${ptr}) to the priority queue ${Q}. Returns a cookie * which can be passed to timerqueue_delete or timerqueue_increase. */ void * timerqueue_add(struct timerqueue *, const struct timeval *, void *); /** * timerqueue_delete(Q, cookie): * Delete the (timeval, ptr) pair associated with the cookie ${cookie} from * the priority queue ${Q}. */ void timerqueue_delete(struct timerqueue *, void *); /** * timerqueue_increase(Q, cookie, tv): * Increase the timer associated with the cookie ${cookie} in the priority * queue ${Q} to ${tv}. */ void timerqueue_increase(struct timerqueue *, void *, const struct timeval *); /** * timerqueue_getmin(Q): * Return a pointer to the least timeval in ${Q}, or NULL if the priority * queue is empty. The pointer will remain valid until the next call to a * timerqueue_* function. This function cannot fail. */ const struct timeval * timerqueue_getmin(struct timerqueue *); /** * timerqueue_getptr(Q, tv): * If the least timeval in ${Q} is less than or equal to ${tv}, return the * associated pointer and remove the pair from the priority queue. If not, * return NULL. This function cannot fail. */ void * timerqueue_getptr(struct timerqueue *, const struct timeval *); /** * timerqueue_free(Q): * Free the timer priority queue ${Q}. */ void timerqueue_free(struct timerqueue *); #endif /* !_TIMERQUEUE_H_ */ spiped-1.3.1/lib/datastruct/mpool.h000644 001751 001751 00000004370 12132205630 020655 0ustar00cpercivacperciva000000 000000 #ifndef _MPOOL_H_ #define _MPOOL_H_ #include /** * Memory allocator cache. Memory allocations can be returned to the pool * and reused by a subsequent allocation without returning all the way to * free/malloc. In effect, this is an optimization for the case where we * know we will want another allocation of the same size soon, at the expense * of allowing the memory to be reused by some other code. */ /** * MPOOL(name, type, size): * Define the functions * * ${type} * mpool_${name}_malloc(void); * void mpool_${name}_free(${type} *); * * which allocate and free structures of type ${type}. Up to ${size} * such structures are kept cached after _free is called in order to * allow future _malloc calls to be rapidly serviced. * * Cached structures will be freed at program exit time in order to aid * in the detection of memory leaks. */ #define MPOOL(name, type, size) \ static struct mpool_##name##_struct { \ size_t stacklen; \ void * top; \ int atexit_set; \ } mpool_##name##_rec = {0, NULL, 0}; \ \ static void \ mpool_##name##_atexit(void) \ { \ void * top; \ \ while ((top = mpool_##name##_rec.top) != NULL) { \ mpool_##name##_rec.top = *(void **)top; \ free(top); \ } \ } \ \ static inline type * \ mpool_##name##_malloc(void) \ { \ type * p; \ \ if (mpool_##name##_rec.stacklen) { \ p = mpool_##name##_rec.top; \ mpool_##name##_rec.top = *(void **)p; \ mpool_##name##_rec.stacklen -= 1; \ } else { \ if (mpool_##name##_rec.atexit_set == 0) { \ atexit(mpool_##name##_atexit); \ mpool_##name##_rec.atexit_set = 1; \ } \ p = malloc((sizeof(type) > sizeof(void *)) ? \ sizeof(type) : sizeof(void *)); \ } \ \ return (p); \ } \ \ static inline void \ mpool_##name##_free(type * p) \ { \ \ if (p == NULL) \ return; \ \ if (mpool_##name##_rec.stacklen < size) { \ *(void **)p = mpool_##name##_rec.top; \ mpool_##name##_rec.top = p; \ mpool_##name##_rec.stacklen += 1; \ } else { \ free(p); \ } \ } \ \ struct mpool_##name##_dummy #endif /* !_MPOOL_H_ */ spiped-1.3.1/lib/datastruct/elasticarray.c000644 001751 001751 00000012301 12132205630 022176 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include "elasticarray.h" struct elasticarray { size_t size; size_t alloc; void * buf; }; /** * resize(EA, nsize): * Resize the virtual buffer for ${EA} to length ${nsize} bytes. The actual * buffer may or may not need to be resized. On failure, the buffer will be * unmodified. */ static int resize(struct elasticarray * EA, size_t nsize) { size_t nalloc; void * nbuf; /* Figure out how large an allocation we want. */ if (EA->alloc < nsize) { /* We need to enlarge the buffer. */ nalloc = EA->alloc * 2; if (nalloc < nsize) nalloc = nsize; } else if (EA->alloc > nsize * 4) { /* We need to shrink the buffer. */ nalloc = nsize * 2; } else { nalloc = EA->alloc; } /* Reallocate if necessary. */ if (nalloc != EA->alloc) { nbuf = realloc(EA->buf, nalloc); if ((nbuf == NULL) && (nalloc > 0)) goto err0; EA->buf = nbuf; EA->alloc = nalloc; } /* Record the new array size. */ EA->size = nsize; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * elasticarray_init(nrec, reclen): * Create and return an elastic array holding ${nrec} (uninitialized) records * of length ${reclen}. Takes O(nrec * reclen) time. */ struct elasticarray * elasticarray_init(size_t nrec, size_t reclen) { struct elasticarray * EA; /* Allocate structure. */ if ((EA = malloc(sizeof(struct elasticarray))) == NULL) goto err0; /* The array is empty for now. */ EA->size = EA->alloc = 0; EA->buf = NULL; /* Reallocate to the requested length. */ if (elasticarray_resize(EA, nrec, reclen)) goto err1; /* Success! */ return (EA); err1: elasticarray_free(EA); err0: /* Failure! */ return (NULL); } /** * elasticarray_resize(EA, nrec, reclen): * Resize the elastic array pointed to by ${EA} to hold ${nrec} records of * length ${reclen}. If ${nrec} exceeds the number of records previously * held by the array, the additional records will be uninitialized. Takes * O(nrec * reclen) time. */ int elasticarray_resize(struct elasticarray * EA, size_t nrec, size_t reclen) { /* Check for overflow. */ if (nrec > SIZE_MAX / reclen) { errno = ENOMEM; goto err0; } /* Resize the buffer. */ if (resize(EA, nrec * reclen)) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * elasticarray_getsize(EA, reclen): * Return the number of length-${reclen} records in the array, rounding down * if there is a partial record (which can only occur if elasticarray_* * functions have been called with different values of reclen). */ size_t elasticarray_getsize(struct elasticarray * EA, size_t reclen) { return (EA->size / reclen); } /** * elasticarray_append(EA, buf, nrec, reclen): * Append to the elastic array ${EA} the ${nrec} records of length ${reclen} * stored in ${buf}. Takes O(nrec * reclen) amortized time. */ int elasticarray_append(struct elasticarray * EA, const void * buf, size_t nrec, size_t reclen) { size_t bufpos = EA->size; /* Check for overflow. */ if ((nrec > SIZE_MAX / reclen) || (nrec * reclen > SIZE_MAX - EA->size)) { errno = ENOMEM; goto err0; } /* Resize the buffer. */ if (resize(EA, EA->size + nrec * reclen)) goto err0; /* Copy bytes in. */ memcpy((void *)((uintptr_t)(EA->buf) + bufpos), buf, nrec * reclen); /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * elasticarray_shrink(EA, nrec, reclen): * Delete the final ${nrec} records of length ${reclen} from the elastic * array ${EA}. If there are fewer than ${nrec} records, all records * present will be deleted. * * As an exception to the normal rule, an elastic array may occupy more than * 4 times the optimal storage immediately following an elasticarray_shrink * call; but only if realloc(3) failed to shrink a memory allocation. */ void elasticarray_shrink(struct elasticarray * EA, size_t nrec, size_t reclen) { size_t nsize; /* Figure out how much to keep. */ if ((nrec > SIZE_MAX / reclen) || (nrec * reclen > EA->size)) nsize = 0; else nsize = EA->size - nrec * reclen; /* Resize the buffer... */ if (resize(EA, nsize)) { /* * ... and if we fail to reallocate, just record the new * length and continue using the old buffer. */ EA->size = nsize; } } /** * elasticarray_truncate(EA): * Release any spare space in the elastic array ${EA}. */ int elasticarray_truncate(struct elasticarray * EA) { void * nbuf; /* If there is spare space, reallocate. */ if (EA->alloc > EA->size) { nbuf = realloc(EA->buf, EA->size); if ((nbuf == NULL) && (EA->size > 0)) goto err0; EA->buf = nbuf; EA->alloc = EA->size; } /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * elasticarray_get(EA, pos, reclen): * Return a pointer to record number ${pos} of length ${reclen} in the * elastic array ${EA}. Takes O(1) time. */ void * elasticarray_get(struct elasticarray * EA, size_t pos, size_t reclen) { return ((void *)((uintptr_t)(EA->buf) + pos * reclen)); } /** * elasticarray_free(EA): * Free the elastic array ${EA}. Takes O(1) time. */ void elasticarray_free(struct elasticarray * EA) { /* Be compatible with free(NULL). */ if (EA == NULL) return; free(EA->buf); free(EA); } spiped-1.3.1/lib/datastruct/ptrheap.c000644 001751 001751 00000020503 12132205630 021161 0ustar00cpercivacperciva000000 000000 #include #include "elasticarray.h" #include "ptrheap.h" ELASTICARRAY_DECL(PTRLIST, ptrlist, void *); struct ptrheap { int (* compar)(void *, const void *, const void *); void (* setreccookie)(void *, void *, size_t); void * cookie; PTRLIST elems; size_t nelems; }; /** * swap(elems, i, j, setreccookie, cookie): * Swap elements ${i} and ${j} in ${elems}. If ${setreccookie} is non-NULL, * invoke ${setreccookie}(${cookie}, elem, pos) for each of the elements and * their new positions in the tree. */ static void swap(PTRLIST elems, size_t i, size_t j, void (* setreccookie)(void *, void *, size_t), void * cookie) { void * tmp; /* Swap the elements. */ tmp = *ptrlist_get(elems, i); *ptrlist_get(elems, i) = *ptrlist_get(elems, j); *ptrlist_get(elems, j) = tmp; /* Notify about the moved elements. */ if (setreccookie != NULL) { setreccookie(cookie, *ptrlist_get(elems, i), i); setreccookie(cookie, *ptrlist_get(elems, j), j); } } /** * heapifyup(elems, i, compar, setreccookie, cookie): * Sift up element ${i} of the elements ${elems}, using the comparison * function ${compar} and the cookie ${cookie}. If elements move and * ${setreccookie} is non-NULL, use it to notify about the updated position * of elements in the heap. */ static void heapifyup(PTRLIST elems, size_t i, int (* compar)(void *, const void *, const void *), void (* setreccookie)(void *, void *, size_t), void * cookie) { /* Iterate up the tree. */ do { /* If we're at the root, we have nothing to do. */ if (i == 0) break; /* If this is >= its parent, we're done. */ if (compar(cookie, *ptrlist_get(elems, i), *ptrlist_get(elems, (i - 1) / 2)) >= 0) break; /* Swap with the parent. */ swap(elems, i, (i - 1) / 2, setreccookie, cookie); /* Move up the tree. */ i = (i - 1) / 2; } while (1); } /** * heapify(elems, i, N, compar, setreccookie, cookie): * Sift down element number ${i} out of ${N} of the elements ${elems}, using * the comparison function ${compar} and the cookie ${cookie}. If elements * move and ${setreccookie} is non-NULL, use it to notify about the updated * position of elements in the heap. */ static void heapify(PTRLIST elems, size_t i, size_t N, int (* compar)(void *, const void *, const void *), void (* setreccookie)(void *, void *, size_t), void * cookie) { size_t min; /* Iterate down the tree. */ do { /* Look for the minimum element out of {i, 2i+1, 2i+2}. */ min = i; /* Is this bigger than element 2i+1? */ if ((2 * i + 1 < N) && (compar(cookie, *ptrlist_get(elems, min), *ptrlist_get(elems, 2 * i + 1)) > 0)) min = 2 * i + 1; /* Is this bigger than element 2i+2? */ if ((2 * i + 2 < N) && (compar(cookie, *ptrlist_get(elems, min), *ptrlist_get(elems, 2 * i + 2)) > 0)) min = 2 * i + 2; /* If the minimum is i, we have heap-property. */ if (min == i) break; /* Move the minimum into position i. */ swap(elems, min, i, setreccookie, cookie); /* Move down the tree. */ i = min; } while (1); } /** * ptrheap_init(compar, setreccookie, cookie): * Create and return an empty heap. The function ${compar}(${cookie}, x, y) * should return less than, equal to, or greater than 0 depending on whether * x is less than, equal to, or greater than y; and if ${setreccookie} is * non-zero it will be called as ${setreccookie}(${cookie}, ${ptr}, ${rc}) to * indicate that the value ${rc} is the current record cookie for the pointer * ${ptr}. The function ${setreccookie} may not make any ptrheap_* calls. */ struct ptrheap * ptrheap_init(int (* compar)(void *, const void *, const void *), void (* setreccookie)(void *, void *, size_t), void * cookie) { /* Let ptrheap_create handle this. */ return (ptrheap_create(compar, setreccookie, cookie, 0, NULL)); } /** * ptrheap_create(compar, setreccookie, cookie, N, ptrs): * Create and return a heap, as in ptrheap_init, but with the ${N} pointers * in ${ptrs} as heap elements. This is faster than creating an empty heap * and adding the elements individually. */ struct ptrheap * ptrheap_create(int (* compar)(void *, const void *, const void *), void (* setreccookie)(void *, void *, size_t), void * cookie, size_t N, void ** ptrs) { struct ptrheap * H; size_t i; /* Allocate structure. */ if ((H = malloc(sizeof(struct ptrheap))) == NULL) goto err0; /* Store parameters. */ H->compar = compar; H->setreccookie = setreccookie; H->cookie = cookie; /* We will have N elements. */ H->nelems = N; /* Allocate space for N heap elements. */ if ((H->elems = ptrlist_init(N)) == NULL) goto err1; /* Copy the heap elements in. */ for (i = 0; i < N; i++) *ptrlist_get(H->elems, i) = ptrs[i]; /* Turn this into a heap. */ for (i = N - 1; i < N; i--) heapify(H->elems, i, N, H->compar, NULL, H->cookie); /* Advise the caller about the record cookies. */ if (H->setreccookie != NULL) for (i = 0; i < N; i++) (H->setreccookie)(H->cookie, *ptrlist_get(H->elems, i), i); /* Success! */ return (H); err1: free(H); err0: /* Failure! */ return (NULL); } /** * ptrheap_add(H, ptr): * Add the pointer ${ptr} to the heap ${H}. */ int ptrheap_add(struct ptrheap * H, void * ptr) { /* Add the element to the end of the heap. */ if (ptrlist_append(H->elems, &ptr, 1)) goto err0; H->nelems += 1; /* Advise the caller about the current location of this record. */ if (H->setreccookie != NULL) (H->setreccookie)(H->cookie, ptr, H->nelems - 1); /* Move the new element up in the tree if necessary. */ heapifyup(H->elems, H->nelems - 1, H->compar, H->setreccookie, H->cookie); /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * ptrheap_getmin(H): * Return the minimum pointer in the heap ${H}. If the heap is empty, NULL * is returned. */ void * ptrheap_getmin(struct ptrheap * H) { /* If we have any elements, the minimum is in position 0. */ if (H->nelems) return (*ptrlist_get(H->elems, 0)); else return (NULL); } /** * ptrheap_delete(H, rc): * Delete from the heap ${H} the element ptr for which the function call * setreccookie(cookie, ptr, ${rc}) was most recently made. */ void ptrheap_delete(struct ptrheap * H, size_t rc) { /* * If the element we're deleting is not at the end of the heap, * replace it with the element which is currently at the end. */ if (rc != H->nelems - 1) { /* Move ptr from position H->nelems - 1 into position rc. */ *ptrlist_get(H->elems, rc) = *ptrlist_get(H->elems, H->nelems - 1); if (H->setreccookie != NULL) (H->setreccookie)(H->cookie, *ptrlist_get(H->elems, rc), rc); /* Is this too small to be in position ${rc}? */ if ((rc > 0) && (H->compar(H->cookie, *ptrlist_get(H->elems, rc), *ptrlist_get(H->elems, (rc - 1) / 2)) < 0)) { /* Swap with the parent, and keep moving up. */ swap(H->elems, rc, (rc - 1) / 2, H->setreccookie, H->cookie); heapifyup(H->elems, (rc - 1) / 2, H->compar, H->setreccookie, H->cookie); } else { /* Maybe we need to move it down instead? */ heapify(H->elems, rc, H->nelems, H->compar, H->setreccookie, H->cookie); } } /* * We've got everything we want to keep in positions 0 .. nelems - 2, * and we have heap-nature, so all we need to do is strip off the * final pointer. */ ptrlist_shrink(H->elems, 1); H->nelems--; } /** * ptrheap_deletemin(H): * Delete the minimum element in the heap ${H}. */ void ptrheap_deletemin(struct ptrheap * H) { /* Let ptrheap_delete handle this. */ ptrheap_delete(H, 0); } /** * ptrheap_increase(H, rc): * Adjust the heap ${H} to account for the fact that the element ptr for * which the function call setreccookie(cookie, ptr, ${rc}) was most recently * made has incrased. */ void ptrheap_increase(struct ptrheap * H, size_t rc) { /* Move the element down if necessary. */ heapify(H->elems, rc, H->nelems, H->compar, H->setreccookie, H->cookie); } /** * ptrheap_increasemin(H): * Adjust the heap ${H} to account for the fact that the (formerly) minimum * element has increased. */ void ptrheap_increasemin(struct ptrheap * H) { /* Move the element down if necessary. */ heapify(H->elems, 0, H->nelems, H->compar, H->setreccookie, H->cookie); } /** * ptrheap_free(H): * Free the pointer heap ${H}. */ void ptrheap_free(struct ptrheap * H) { /* Be compatible with free(NULL). */ if (H == NULL) return; ptrlist_free(H->elems); free(H); } spiped-1.3.1/lib/datastruct/timerqueue.c000644 001751 001751 00000011350 12132205630 021703 0ustar00cpercivacperciva000000 000000 #include #include #include #include "ptrheap.h" #include "timerqueue.h" struct timerqueue { struct ptrheap * H; }; struct timerrec { struct timeval tv; size_t rc; void * ptr; }; /* Compare two timevals. */ static int tvcmp(const struct timeval * x, const struct timeval * y) { /* Does one have more seconds? */ if (x->tv_sec > y->tv_sec) return (1); if (x->tv_sec < y->tv_sec) return (-1); /* Does one have more microseconds? */ if (x->tv_usec > y->tv_usec) return (1); if (x->tv_usec < y->tv_usec) return (-1); /* They must be equal. */ return (0); } /* Record-comparison callback from ptrheap. */ static int compar(void * cookie, const void * x, const void * y) { const struct timerrec *_x = x; const struct timerrec *_y = y; (void)cookie; /* UNUSED */ return (tvcmp(&_x->tv, &_y->tv)); } /* Cookie-recording callback from ptrheap. */ static void setreccookie(void * cookie, void * ptr, size_t rc) { struct timerrec * rec = ptr; (void)cookie; /* UNUSED */ rec->rc = rc; } /** * timerqueue_init(void): * Create and return an empty timer priority queue. */ struct timerqueue * timerqueue_init(void) { struct timerqueue * Q; /* Allocate structure. */ if ((Q = malloc(sizeof(struct timerqueue))) == NULL) goto err0; /* Allocate heap. */ if ((Q->H = ptrheap_init(compar, setreccookie, Q)) == NULL) goto err1; /* Success! */ return (Q); err1: free(Q); err0: /* Failure! */ return (NULL); } /** * timerqueue_add(Q, tv, ptr): * Add the pair (${tv}, ${ptr}) to the priority queue ${Q}. Returns a cookie * which can be passed to timerqueue_delete or timerqueue_increase. */ void * timerqueue_add(struct timerqueue * Q, const struct timeval * tv, void * ptr) { struct timerrec * r; /* Allocate (timeval, ptr) pair record. */ if ((r = malloc(sizeof(struct timerrec))) == NULL) goto err0; /* Fill in values. */ memcpy(&r->tv, tv, sizeof(struct timeval)); r->ptr = ptr; /* * Add the record to the heap. The value r->rc will be filled in * by setreccookie which will be called by ptrheap_add. */ if (ptrheap_add(Q->H, r)) goto err1; /* Success! */ return (r); err1: free(r); err0: /* Failure! */ return (NULL); } /** * timerqueue_delete(Q, cookie): * Delete the (timeval, ptr) pair associated with the cookie ${cookie} from * the priority queue ${Q}. */ void timerqueue_delete(struct timerqueue * Q, void * cookie) { struct timerrec * r = cookie; /* Remove the record from the heap. */ ptrheap_delete(Q->H, r->rc); /* Free the record. */ free(r); } /** * timerqueue_increase(Q, cookie, tv): * Increase the timer associated with the cookie ${cookie} in the priority * queue ${Q} to ${tv}. */ void timerqueue_increase(struct timerqueue * Q, void * cookie, const struct timeval * tv) { struct timerrec * r = cookie; /* Adjust timer value. */ memcpy(&r->tv, tv, sizeof(struct timeval)); /* Inform the heap that the record value has increased. */ ptrheap_increase(Q->H, r->rc); } /** * timerqueue_getmin(Q): * Return a pointer to the least timeval in ${Q}, or NULL if the priority * queue is empty. The pointer will remain valid until the next call to a * timerqueue_* function. This function cannot fail. */ const struct timeval * timerqueue_getmin(struct timerqueue * Q) { struct timerrec * r; /* Get the minimum element from the heap. */ r = ptrheap_getmin(Q->H); /* If we have an element, return its timeval; otherwise, NULL. */ if (r != NULL) return (&r->tv); else return (NULL); } /** * timerqueue_getptr(Q, tv): * If the least timeval in ${Q} is less than or equal to ${tv}, return the * associated pointer and remove the pair from the priority queue. If not, * return NULL. */ void * timerqueue_getptr(struct timerqueue * Q, const struct timeval * tv) { struct timerrec * r; void * ptr; /* * Get the minimum element from the heap. Return NULL if the heap * has no minimum element (i.e., is empty). */ if ((r = ptrheap_getmin(Q->H)) == NULL) return (NULL); /* If the minimum timeval is greater than ${tv}, return NULL. */ if (tvcmp(&r->tv, tv) > 0) return (NULL); /* Remove this record from the heap. */ ptrheap_deletemin(Q->H); /* Extract its pointer. */ ptr = r->ptr; /* Free the record. */ free(r); /* * And finally return the pointer which was associated with the * (formerly) minimum timeval in the heap. */ return (ptr); } /** * timerqueue_free(Q): * Free the timer priority queue ${Q}. */ void timerqueue_free(struct timerqueue * Q) { struct timerrec * r; /* Extract elements from the heap and free them one by one. */ while ((r = ptrheap_getmin(Q->H)) != NULL) { free(r); ptrheap_deletemin(Q->H); } /* Free the heap. */ ptrheap_free(Q->H); /* Free the timer priority queue structure. */ free(Q); } spiped-1.3.1/lib/util/sock.c000644 001751 001751 00000023772 12132205630 017267 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include #include #include #include #include #include "imalloc.h" #include "warnp.h" #include "sock.h" #include "sock_internal.h" /* Convert a path into a socket address. */ static struct sock_addr ** sock_resolve_unix(const char * addr) { struct sock_addr ** sas; struct sock_addr * sa; struct sockaddr_un * sa_un; /* Allocate and populate a sockaddr_un structure. */ if ((sa_un = malloc(sizeof(struct sockaddr_un))) == NULL) goto err0; memset(sa_un, 0, sizeof(struct sockaddr_un)); sa_un->sun_family = AF_UNIX; if (strlen(addr) >= sizeof(sa_un->sun_path)) { warn0("socket path too long: %s", addr); goto err1; } strcpy(sa_un->sun_path, addr); /* Allocate and populate our wrapper. */ if ((sa = malloc(sizeof(struct sock_addr))) == NULL) goto err1; sa->ai_family = AF_UNIX; sa->ai_socktype = SOCK_STREAM; sa->name = (struct sockaddr *)sa_un; sa->namelen = sizeof(struct sockaddr_un); /* Allocate and populate an array of pointers. */ if ((sas = malloc(2 * sizeof(struct sock_addr *))) == NULL) goto err2; sas[0] = sa; sas[1] = NULL; /* Success! */ return (sas); err2: free(sa); err1: free(sa_un); err0: /* Failure! */ return (NULL); } /* Resolve a host into a list of socket addresses. */ static struct sock_addr ** sock_resolve_host(const char * addr, const char * ports) { struct addrinfo hints; struct addrinfo * res; struct addrinfo * r; struct sock_addr ** sas; size_t n; int error; /* Create hints structure. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; /* Perform DNS lookup. */ if ((error = getaddrinfo(addr, ports, &hints, &res)) != 0) { warn0("Error looking up %s: %s", addr, gai_strerror(error)); goto err0; } /* Count addresses returned. */ for (n = 0, r = res; r != NULL; r = r->ai_next) n++; /* Allocate our response array. */ if (IMALLOC(sas, n + 1, struct sock_addr *)) goto err1; /* Create address structures. */ for (n = 0, r = res; r != NULL; n++, r = r->ai_next) { /* Allocate a structure. */ if ((sas[n] = malloc(sizeof(struct sock_addr))) == NULL) goto err2; /* Copy in the address metadata. */ sas[n]->ai_family = r->ai_family; sas[n]->ai_socktype = r->ai_socktype; sas[n]->namelen = r->ai_addrlen; /* Duplicate the address. */ if ((sas[n]->name = malloc(sas[n]->namelen)) == NULL) goto err3; memcpy(sas[n]->name, r->ai_addr, sas[n]->namelen); } /* Terminate array with a NULL. */ sas[n] = NULL; /* Free the linked list of addresses returned by getaddrinfo. */ freeaddrinfo(res); /* Success! */ return (sas); err3: free(sas[n]); err2: for (; n > 0; n--) { free(sas[n - 1]->name); free(sas[n - 1]); } free(sas); err1: freeaddrinfo(res); err0: /* Failure! */ return (NULL); } /* Parse an IPv6 address into a socket address. */ static struct sock_addr ** sock_resolve_ipv6(const char * addr, in_port_t p) { struct sock_addr ** sas; struct sock_addr * sa; struct sockaddr_in6 * sin6; /* Allocate and populate a sockaddr_in6 structure. */ if ((sin6 = malloc(sizeof(struct sockaddr_in6))) == NULL) goto err0; memset(sin6, 0, sizeof(struct sockaddr_in6)); sin6->sin6_family = AF_INET6; sin6->sin6_port = htons(p); if (inet_pton(AF_INET6, addr, &sin6->sin6_addr) != 1) { warn0("Error parsing IP address: %s", addr); goto err1; } /* Allocate and populate our wrapper. */ if ((sa = malloc(sizeof(struct sock_addr))) == NULL) goto err1; sa->ai_family = AF_INET6; sa->ai_socktype = SOCK_STREAM; sa->name = (struct sockaddr *)sin6; sa->namelen = sizeof(struct sockaddr_in6); /* Allocate and populate an array of pointers. */ if ((sas = malloc(2 * sizeof(struct sock_addr *))) == NULL) goto err2; sas[0] = sa; sas[1] = NULL; /* Success! */ return (sas); err2: free(sa); err1: free(sin6); err0: /* Failure! */ return (NULL); } /* Parse an IPv4 address into a socket address. */ static struct sock_addr ** sock_resolve_ipv4(const char * addr, in_port_t p) { struct sock_addr ** sas; struct sock_addr * sa; struct sockaddr_in * sin; /* Allocate and populate a sockaddr_in structure. */ if ((sin = malloc(sizeof(struct sockaddr_in))) == NULL) goto err0; memset(sin, 0, sizeof(struct sockaddr_in)); sin->sin_family = AF_INET; sin->sin_port = htons(p); if (inet_pton(AF_INET, addr, &sin->sin_addr) != 1) { warn0("Error parsing IP address: %s", addr); goto err1; } /* Allocate and populate our wrapper. */ if ((sa = malloc(sizeof(struct sock_addr))) == NULL) goto err1; sa->ai_family = AF_INET; sa->ai_socktype = SOCK_STREAM; sa->name = (struct sockaddr *)sin; sa->namelen = sizeof(struct sockaddr_in); /* Allocate and populate an array of pointers. */ if ((sas = malloc(2 * sizeof(struct sock_addr *))) == NULL) goto err2; sas[0] = sa; sas[1] = NULL; /* Success! */ return (sas); err2: free(sa); err1: free(sin); err0: /* Failure! */ return (NULL); } /** * sock_resolve(addr): * Return a NULL-terminated array of pointers to sock_addr structures. */ struct sock_addr ** sock_resolve(const char * addr) { struct sock_addr ** res; char * s; char * ports; char * ips; long p; /* If the address starts with '/', it's a unix socket. */ if (addr[0] == '/') { res = sock_resolve_unix(addr); goto done; } /* Copy the address so that we can mangle it. */ if ((s = strdup(addr)) == NULL) goto err0; /* The address should end with :port. Look for the last ':'. */ if ((ports = strrchr(s, ':')) == NULL) { warn0("Address must contain port number: %s", s); goto err1; } *ports++ = '\0'; /* If the address doesn't start with '[', it's a host name. */ if (s[0] != '[') { res = sock_resolve_host(s, ports); goto done1; } /* The address (sans :port) should end with ']'. */ if (s[strlen(s) - 1] != ']') { warn0("Invalid [IP address]: %s", s); goto err1; } /* Extract the IP address string. */ ips = &s[1]; ips[strlen(ips) - 1] = '\0'; /* * Parse the port number. If strtol fails to parse the port number, * it will return 0; but that's fine since port 0 is invalid anyway. */ p = strtol(ports, NULL, 10); if ((p <= 0) || (p >= 65536)) { warn0("Invalid port number: %s", ports); goto err1; } /* If the IP address contains ':', it's IPv6; otherwise, IPv4. */ if (strrchr(ips, ':') != NULL) res = sock_resolve_ipv6(ips, p); else res = sock_resolve_ipv4(ips, p); done1: /* Free string allocated by strdup. */ free(s); done: /* Return result from sock_resolve_foo. */ return (res); err1: free(s); err0: /* Failure! */ return (NULL); } /** * sock_listener(sa): * Create a socket, set SO_REUSEADDR, bind it to the socket address ${sa}, * mark it for listening, and mark it as non-blocking. */ int sock_listener(const struct sock_addr * sa) { int s; int val = 1; /* Create a socket. */ if ((s = socket(sa->ai_family, sa->ai_socktype, 0)) == -1) { warnp("socket(%d, %d)", sa->ai_family, sa->ai_socktype); goto err0; } /* Set SO_REUSEADDR. */ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) { warnp("setsockopt(SO_REUSEADDR)"); goto err1; } /* Bind the socket. */ if (bind(s, sa->name, sa->namelen)) { warnp("error binding socket"); goto err1; } /* Mark the socket as listening. */ if (listen(s, 10)) { warnp("error marking socket as listening"); goto err1; } /* Make the socket as non-blocking. */ if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { warnp("error marking socket as non-blocking"); goto err1; } /* Success! */ return (s); err1: close(s); err0: /* Failure! */ return (-1); } /** * sock_connect(sas): * Iterate through the addresses in ${sas}, attempting to create a socket and * connect (blockingly). Once connected, stop iterating, mark the socket as * non-blocking, and return it. */ int sock_connect(struct sock_addr * const * sas) { int s = -1; /* Iterate through the addresses provided. */ for (; sas[0] != NULL; sas++) { /* Create a socket. */ if ((s = socket(sas[0]->ai_family, sas[0]->ai_socktype, 0)) == -1) continue; /* Attempt to connect. */ if (connect(s, sas[0]->name, sas[0]->namelen) == 0) break; /* Close the socket; this address didn't work. */ close(s); } /* Did we manage to connect? */ if (sas[0] == NULL) { warn0("Could not connect"); goto err0; } /* Mark the socket as non-blocking. */ if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { warnp("Cannot make connection non-blocking"); goto err1; } /* Success! */ return (s); err1: close(s); err0: /* Failure! */ return (-1); } /** * sock_connect_nb(sa): * Create a socket, mark it as non-blocking, and attempt to connect to the * address ${sa}. Return the socket (connected or in the process of * connecting) or -1 on error. */ int sock_connect_nb(const struct sock_addr * sa) { int s; /* Create a socket. */ if ((s = socket(sa->ai_family, sa->ai_socktype, 0)) == -1) goto err0; /* Mark the socket as non-blocking. */ if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) { warnp("Cannot make socket non-blocking"); goto err1; } /* Attempt to connect. */ if ((connect(s, sa->name, sa->namelen) == -1) && (errno != EINPROGRESS) && (errno == EINTR)) goto err1; /* We have a connect(ed|ing) socket. */ return (s); err1: close(s); err0: /* We failed to connect to this address. */ return (-1); } /** * sock_addr_free(sa): * Free the provided sock_addr structure. */ void sock_addr_free(struct sock_addr * sa) { /* Compatibility with free(NULL). */ if (sa == NULL) return; /* Free the protocol-specific address structure and our struct. */ free(sa->name); free(sa); } /** * sock_addr_freelist(sas): * Free the provided NULL-terminated array of sock_addr structures. */ void sock_addr_freelist(struct sock_addr ** sas) { struct sock_addr ** p; /* Compatibility with free(NULL). */ if (sas == NULL) return; /* Free structures until we hit NULL. */ for (p = sas; *p != NULL; p++) sock_addr_free(*p); /* Free the list. */ free(sas); } spiped-1.3.1/lib/util/entropy.c000644 001751 001751 00000002720 12132205630 020016 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include "warnp.h" #include "entropy.h" /** * XXX Portability * XXX We obtain random bytes from the operating system by opening * XXX /dev/urandom and reading them from that device; this works on * XXX modern UNIX-like operating systems but not on systems like * XXX win32 where there is no concept of /dev/urandom. */ /** * entropy_read(buf, buflen): * Fill the given buffer with random bytes provided by the operating system. */ int entropy_read(uint8_t * buf, size_t buflen) { int fd; ssize_t lenread; /* Sanity-check the buffer size. */ if (buflen > SSIZE_MAX) { warn0("Programmer error: " "Trying to read insane amount of random data: %zu", buflen); goto err0; } /* Open /dev/urandom. */ if ((fd = open("/dev/urandom", O_RDONLY)) == -1) { warnp("open(/dev/urandom)"); goto err0; } /* Read bytes until we have filled the buffer. */ while (buflen > 0) { if ((lenread = read(fd, buf, buflen)) == -1) { warnp("read(/dev/urandom)"); goto err1; } /* The random device should never EOF. */ if (lenread == 0) { warn0("EOF on /dev/urandom?"); goto err1; } /* We're partly done. */ buf += lenread; buflen -= lenread; } /* Close the device. */ while (close(fd) == -1) { if (errno != EINTR) { warnp("close(/dev/urandom)"); goto err0; } } /* Success! */ return (0); err1: close(fd); err0: /* Failure! */ return (-1); } spiped-1.3.1/lib/util/sock_internal.h000644 001751 001751 00000000364 12132205630 021160 0ustar00cpercivacperciva000000 000000 #ifndef _SOCK_INTERNAL_H_ #define _SOCK_INTERNAL_H_ #include /* Socket address structure. */ struct sock_addr { int ai_family; int ai_socktype; struct sockaddr * name; socklen_t namelen; }; #endif /* !_SOCK_INTERNAL_H_ */ spiped-1.3.1/lib/util/sock_util.h000644 001751 001751 00000002550 12132205630 020320 0ustar00cpercivacperciva000000 000000 #ifndef _SOCK_UTIL_H_ #define _SOCK_UTIL_H_ #include /* Opaque address structure. */ struct sock_addr; /** * sock_addr_cmp(sa1, sa2): * Return non-zero iff the socket addresses ${sa1} and ${sa2} are different. */ int sock_addr_cmp(const struct sock_addr *, const struct sock_addr *); /** * sock_addr_dup(sa): * Duplicate the provided socket address. */ struct sock_addr * sock_addr_dup(const struct sock_addr *); /** * sock_addr_duplist(sas): * Duplicate the provided list of socket addresses. */ struct sock_addr ** sock_addr_duplist(struct sock_addr * const *); /** * sock_addr_serialize(sa, buf, buflen): * Allocate a buffer and serialize the socket address ${sa} into it. Return * the buffer via ${buf} and its length via ${buflen}. The serialization is * machine and operating system dependent. */ int sock_addr_serialize(const struct sock_addr *, uint8_t **, size_t *); /** * sock_addr_deserialize(buf, buflen): * Deserialize the ${buflen}-byte serialized socket address from ${buf}. */ struct sock_addr * sock_addr_deserialize(const uint8_t *, size_t); /** * sock_addr_prettyprint(sa): * Allocate and return a string in one of the forms * /path/to/unix/socket * [ip.v4.ad.dr]:port * [ipv6:add::ress]:port * representing the provided socket address. */ char * sock_addr_prettyprint(const struct sock_addr *); #endif /* !_SOCK_H_ */ spiped-1.3.1/lib/util/sysendian.h000644 001751 001751 00000005775 12132205630 020335 0ustar00cpercivacperciva000000 000000 #ifndef _SYSENDIAN_H_ #define _SYSENDIAN_H_ #include /* Avoid namespace collisions with BSD . */ #define be16dec compat_be16dec #define be16enc compat_be16enc #define be32dec compat_be32dec #define be32enc compat_be32enc #define be64dec compat_be64dec #define be64enc compat_be64enc #define le16dec compat_le16dec #define le16enc compat_le16enc #define le32dec compat_le32dec #define le32enc compat_le32enc #define le64dec compat_le64dec #define le64enc compat_le64enc static inline uint16_t be16dec(const void *pp) { const uint8_t *p = (uint8_t const *)pp; return ((uint16_t)(p[1]) + ((uint16_t)(p[0]) << 8)); } static inline void be16enc(void *pp, uint16_t x) { uint8_t * p = (uint8_t *)pp; p[1] = x & 0xff; p[0] = (x >> 8) & 0xff; } static inline uint32_t be32dec(const void *pp) { const uint8_t *p = (uint8_t const *)pp; return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) + ((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24)); } static inline void be32enc(void *pp, uint32_t x) { uint8_t * p = (uint8_t *)pp; p[3] = x & 0xff; p[2] = (x >> 8) & 0xff; p[1] = (x >> 16) & 0xff; p[0] = (x >> 24) & 0xff; } static inline uint64_t be64dec(const void *pp) { const uint8_t *p = (uint8_t const *)pp; return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) + ((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) + ((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) + ((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56)); } static inline void be64enc(void *pp, uint64_t x) { uint8_t * p = (uint8_t *)pp; p[7] = x & 0xff; p[6] = (x >> 8) & 0xff; p[5] = (x >> 16) & 0xff; p[4] = (x >> 24) & 0xff; p[3] = (x >> 32) & 0xff; p[2] = (x >> 40) & 0xff; p[1] = (x >> 48) & 0xff; p[0] = (x >> 56) & 0xff; } static inline uint16_t le16dec(const void *pp) { const uint8_t *p = (uint8_t const *)pp; return ((uint16_t)(p[0]) + ((uint16_t)(p[1]) << 8)); } static inline void le16enc(void *pp, uint16_t x) { uint8_t * p = (uint8_t *)pp; p[0] = x & 0xff; p[1] = (x >> 8) & 0xff; } static inline uint32_t le32dec(const void *pp) { const uint8_t *p = (uint8_t const *)pp; return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) + ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24)); } static inline void le32enc(void *pp, uint32_t x) { uint8_t * p = (uint8_t *)pp; p[0] = x & 0xff; p[1] = (x >> 8) & 0xff; p[2] = (x >> 16) & 0xff; p[3] = (x >> 24) & 0xff; } static inline uint64_t le64dec(const void *pp) { const uint8_t *p = (uint8_t const *)pp; return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) + ((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) + ((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) + ((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56)); } static inline void le64enc(void *pp, uint64_t x) { uint8_t * p = (uint8_t *)pp; p[0] = x & 0xff; p[1] = (x >> 8) & 0xff; p[2] = (x >> 16) & 0xff; p[3] = (x >> 24) & 0xff; p[4] = (x >> 32) & 0xff; p[5] = (x >> 40) & 0xff; p[6] = (x >> 48) & 0xff; p[7] = (x >> 56) & 0xff; } #endif /* !_SYSENDIAN_H_ */ spiped-1.3.1/lib/util/sock.h000644 001751 001751 00000002564 12132205630 017270 0ustar00cpercivacperciva000000 000000 #ifndef _SOCK_H_ #define _SOCK_H_ /** * Address strings are of the following forms: * /path/to/unix/socket * [ip.v4.ad.dr]:port * [ipv6:add::ress]:port * host.name:port */ /* Opaque address structure. */ struct sock_addr; /** * sock_resolve(addr): * Return a NULL-terminated array of pointers to sock_addr structures. */ struct sock_addr ** sock_resolve(const char *); /** * sock_listener(sa): * Create a socket, set SO_REUSEADDR, bind it to the socket address ${sa}, * mark it for listening, and mark it as non-blocking. */ int sock_listener(const struct sock_addr *); /** * sock_connect(sas): * Iterate through the addresses in ${sas}, attempting to create a socket and * connect (blockingly). Once connected, stop iterating, mark the socket as * non-blocking, and return it. */ int sock_connect(struct sock_addr * const *); /** * sock_connect_nb(sa): * Create a socket, mark it as non-blocking, and attempt to connect to the * address ${sa}. Return the socket (connected or in the process of * connecting) or -1 on error. */ int sock_connect_nb(const struct sock_addr *); /** * sock_addr_free(sa): * Free the provided sock_addr structure. */ void sock_addr_free(struct sock_addr *); /** * sock_addr_freelist(sas): * Free the provided NULL-terminated array of sock_addr structures. */ void sock_addr_freelist(struct sock_addr **); #endif /* !_SOCK_H_ */ spiped-1.3.1/lib/util/entropy.h000644 001751 001751 00000000405 12132205630 020021 0ustar00cpercivacperciva000000 000000 #ifndef _ENTROPY_H_ #define _ENTROPY_H_ #include #include /** * entropy_read(buf, buflen): * Fill the given buffer with random bytes provided by the operating system. */ int entropy_read(uint8_t *, size_t); #endif /* !_ENTROPY_H_ */ spiped-1.3.1/lib/util/daemonize.c000644 001751 001751 00000004541 12132205630 020274 0ustar00cpercivacperciva000000 000000 #include #include #include #include "noeintr.h" #include "warnp.h" #include "daemonize.h" /** * daemonize(spid): * Daemonize and write the process ID in decimal to a file named ${spid}. * The parent process will exit only after the child has written its pid. * On success, the child will return 0; on failure, the parent will return * -1. */ int daemonize(const char * spid) { FILE * f; int fd[2]; char dummy = 0; /* * Create a pipe for the child to notify the parent when it has * finished daemonizing. */ if (pipe(fd)) { warnp("pipe"); goto err0; } /* * Fork into the parent process (which waits for a poke and exits) * and the child process (which keeps going). */ switch (fork()) { case -1: /* Fork failed. */ warnp("fork"); goto err2; case 0: /* In child process. */ break; default: /* * In parent process. Close write end of pipe so that if the * client dies we will notice the pipe being reset. */ while (close(fd[1])) { if (errno == EINTR) continue; warnp("close"); goto err1; } do { switch (read(fd[0], &dummy, 1)) { case -1: /* Error in read. */ break; case 0: /* EOF -- the child died without poking us. */ goto err1; case 1: /* We have been poked by the child. Exit. */ _exit(0); } /* Anything other than EINTR is bad. */ if (errno != EINTR) { warnp("read"); goto err1; } } while (1); } /* Set ourselves to be a session leader. */ if (setsid() == -1) { warnp("setsid"); goto die; } /* Write out our pid file. */ if ((f = fopen(spid, "w")) == NULL) { warnp("fopen(%s)", spid); goto die; } if (fprintf(f, "%d", getpid()) < 0) { warnp("fprintf"); goto die; } if (fclose(f)) { warnp("fclose"); goto die; } /* Tell the parent to suicide. */ if (noeintr_write(fd[1], &dummy, 1) == -1) { warnp("write"); goto die; } /* Close the pipe. */ while (close(fd[0])) { if (errno == EINTR) continue; warnp("close"); goto die; } while (close(fd[1])) { if (errno == EINTR) continue; warnp("close"); goto die; } /* Success! */ return (0); err2: close(fd[1]); err1: close(fd[0]); err0: /* Failure! */ return (-1); die: /* * We're in the child and something bad happened; the parent will be * notified when we die thanks to the pipe being closed. */ _exit(0); } spiped-1.3.1/lib/util/noeintr.c000644 001751 001751 00000002161 12132205630 017773 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include "noeintr.h" /** * noeintr_write(d, buf, nbytes): * Write ${nbytes} bytes of data from ${buf} to the file descriptor ${d} per * the write(2) system call, but looping until completion if interrupted by * a signal. Return ${nbytes} on success or -1 on error. */ ssize_t noeintr_write(int d, const void * buf, size_t nbyte) { const uint8_t * p = buf; size_t len = nbyte; ssize_t lenwrit; /* Implementation-defined: Don't allow oversized writes. */ assert(nbyte <= SSIZE_MAX); /* Loop until we have no data left to write. */ while (len > 0) { if ((lenwrit = write(d, p, len)) == -1) { /* EINTR is harmless. */ if (errno == EINTR) continue; /* Anything else isn't. */ goto err0; } /* Sanity check. */ assert(lenwrit >= 0); assert(lenwrit <= (ssize_t)len); /* * We might have done a partial write; advance the buffer * pointer and adjust the remaining write length. */ p += lenwrit; len -= lenwrit; } /* Success! */ return (nbyte); err0: /* Failure! */ return (-1); } spiped-1.3.1/lib/util/daemonize.h000644 001751 001751 00000000315 12132205630 020274 0ustar00cpercivacperciva000000 000000 #ifndef _DAEMONIZE_H_ #define _DAEMONIZE_H_ /** * daemonize(spid): * Daemonize and write the process ID in decimal to a file named ${spid}. */ int daemonize(const char *); #endif /* !_DAEMONIZE_H_ */ spiped-1.3.1/lib/util/noeintr.h000644 001751 001751 00000000607 12132205630 020003 0ustar00cpercivacperciva000000 000000 #ifndef _NOEINTR_H_ #define _NOEINTR_H_ #include /** * noeintr_write(d, buf, nbytes): * Write ${nbytes} bytes of data from ${buf} to the file descriptor ${d} per * the write(2) system call, but looping until completion if interrupted by * a signal. Return ${nbytes} on success or -1 on error. */ ssize_t noeintr_write(int, const void *, size_t); #endif /* _NOEINTR_H_ */ spiped-1.3.1/lib/util/monoclock.c000644 001751 001751 00000001235 12132205630 020302 0ustar00cpercivacperciva000000 000000 #include #include #include "warnp.h" #include "monoclock.h" /** * monoclock_get(tv): * Store the current time in ${tv}. If CLOCK_MONOTONIC is available, use * that clock; otherwise, use gettimeofday(2). */ int monoclock_get(struct timeval * tv) { #ifdef CLOCK_MONOTONIC struct timespec tp; #endif #ifdef CLOCK_MONOTONIC if (clock_gettime(CLOCK_MONOTONIC, &tp)) { warnp("clock_gettime(CLOCK_MONOTONIC)"); goto err0; } tv->tv_sec = tp.tv_sec; tv->tv_usec = tp.tv_nsec / 1000; #else if (gettimeofday(tv, NULL)) { warnp("gettimeofday"); goto err0; } #endif /* Success! */ return (0); err0: /* Failure! */ return (-1); } spiped-1.3.1/lib/util/imalloc.h000644 001751 001751 00000001246 12132205630 017745 0ustar00cpercivacperciva000000 000000 #ifndef _IMALLOC_H_ #define _IMALLOC_H_ #include #include #include /** * imalloc(nrec, reclen): * Allocate ${nrec} records of length ${reclen}. Check for size_t overflow. */ static inline void * imalloc(size_t nrec, size_t reclen) { if (nrec > SIZE_MAX / reclen) { errno = ENOMEM; return (NULL); } else { return (malloc(nrec * reclen)); } } /** * IMALLOC(p, nrec, type): * Allocate ${nrec} records of type ${type} and store the pointer in ${p}. * Return non-zero on failure. */ #define IMALLOC(p, nrec, type) \ ((((p) = (type *)imalloc((nrec), sizeof(type))) == NULL) && \ ((nrec) > 0)) #endif /* !_IMALLOC_H_ */ spiped-1.3.1/lib/util/asprintf.c000644 001751 001751 00000001424 12132205630 020144 0ustar00cpercivacperciva000000 000000 #include #include #include #include "asprintf.h" /** * asprintf(ret, format, ...): * Do asprintf(3) like GNU and BSD do. */ int asprintf(char **ret, const char *format, ...) { va_list ap; int len; size_t buflen; /* Figure out how long the string needs to be. */ va_start(ap, format); len = vsnprintf(NULL, 0, format, ap); va_end(ap); /* Did we fail? */ if (len < 0) goto err0; buflen = (size_t)(len) + 1; /* Allocate memory. */ if ((*ret = malloc(buflen)) == NULL) goto err0; /* Actually generate the string. */ va_start(ap, format); len = vsnprintf(*ret, buflen, format, ap); va_end(ap); /* Did we fail? */ if (len < 0) goto err1; /* Success! */ return (len); err1: free(*ret); err0: /* Failure! */ return (-1); } spiped-1.3.1/lib/util/warnp.c000644 001751 001751 00000002477 12132205630 017456 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include "warnp.h" static int initialized = 0; static char * name = NULL; /* Free the name string. */ static void done(void) { free(name); name = NULL; } /** * warnp_setprogname(progname): * Set the program name to be used by warn() and warnx() to ${progname}. */ void warnp_setprogname(const char * progname) { const char * p; /* Free the name if we already have one. */ free(name); /* Find the last segment of the program name. */ for (p = progname; progname[0] != '\0'; progname++) if (progname[0] == '/') p = progname + 1; /* Copy the name string. */ name = strdup(p); /* If we haven't already done so, register our exit handler. */ if (initialized == 0) { atexit(done); initialized = 1; } } void warn(const char * fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "%s", (name != NULL) ? name : "(unknown)"); if (fmt != NULL) { fprintf(stderr, ": "); vfprintf(stderr, fmt, ap); } fprintf(stderr, ": %s\n", strerror(errno)); va_end(ap); } void warnx(const char * fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "%s", (name != NULL) ? name : "(unknown)"); if (fmt != NULL) { fprintf(stderr, ": "); vfprintf(stderr, fmt, ap); } fprintf(stderr, "\n"); va_end(ap); } spiped-1.3.1/lib/util/monoclock.h000644 001751 001751 00000000435 12132205630 020310 0ustar00cpercivacperciva000000 000000 #ifndef _MONOCLOCK_H_ #define _MONOCLOCK_H_ #include /** * monoclock_get(tv): * Store the current time in ${tv}. If CLOCK_MONOTONIC is available, use * that clock; otherwise, use gettimeofday(2). */ int monoclock_get(struct timeval *); #endif /* !_MONOCLOCK_H_ */ spiped-1.3.1/lib/util/asprintf.h000644 001751 001751 00000000500 12132205630 020143 0ustar00cpercivacperciva000000 000000 #ifndef _ASPRINTF_H_ #define _ASPRINTF_H_ /* Avoid namespace collisions with BSD/GNU asprintf. */ #ifdef asprintf #undef asprintf #endif #define asprintf compat_asprintf /** * asprintf(ret, format, ...): * Do asprintf(3) like GNU and BSD do. */ int asprintf(char **, const char *, ...); #endif /* !_ASPRINTF_H_ */ spiped-1.3.1/lib/util/warnp.h000644 001751 001751 00000002513 12132205630 017452 0ustar00cpercivacperciva000000 000000 #ifndef _WARNP_H_ #define _WARNP_H_ #include /* Avoid namespace collisions with BSD . */ #define warn compat_warn #define warnx compat_warnx /** * warnp_setprogname(progname): * Set the program name to be used by warn() and warnx() to ${progname}. */ void warnp_setprogname(const char *); #define WARNP_INIT do { \ if (argv[0] != NULL) \ warnp_setprogname(argv[0]); \ } while (0) /* As in BSD . */ void warn(const char *, ...); void warnx(const char *, ...); /* * If compiled with DEBUG defined, print __FILE__ and __LINE__. */ #ifdef DEBUG #define warnline do { \ warnx("%s, %d", __FILE__, __LINE__); \ } while (0) #else #define warnline #endif /* * Call warn(3) or warnx(3) depending upon whether errno == 0; and clear * errno (so that the standard error message isn't repeated later). */ #define warnp(...) do { \ warnline; \ if (errno != 0) { \ warn(__VA_ARGS__); \ errno = 0; \ } else \ warnx(__VA_ARGS__); \ } while (0) /* * Call warnx(3) and set errno == 0. Unlike warnp, this should be used * in cases where we're reporting a problem which we discover ourselves * rather than one which is reported to us from a library or the kernel. */ #define warn0(...) do { \ warnline; \ warnx(__VA_ARGS__); \ errno = 0; \ } while (0) #endif /* !_WARNP_H_ */ spiped-1.3.1/lib/util/sock_util.c000644 001751 001751 00000013264 12132205630 020317 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include "asprintf.h" #include "sock.h" #include "sock_util.h" #include "sock_internal.h" /** * sock_addr_cmp(sa1, sa2): * Return non-zero iff the socket addresses ${sa1} and ${sa2} are different. */ int sock_addr_cmp(const struct sock_addr * sa1, const struct sock_addr * sa2) { /* Family, socket type, and name length must match. */ if ((sa1->ai_family != sa2->ai_family) || (sa1->ai_socktype != sa2->ai_socktype) || (sa1->namelen != sa2->namelen)) return (1); /* The required length of the sockaddr must match. */ if (memcmp(sa1->name, sa2->name, sa1->namelen) != 0) return (1); /* Everything matched. */ return (0); } /** * sock_addr_dup(sa): * Duplicate the provided socket address. */ struct sock_addr * sock_addr_dup(const struct sock_addr * sa) { struct sock_addr * sa2; /* Allocate a struct sock_addr and copy fields. */ if ((sa2 = malloc(sizeof(struct sock_addr))) == NULL) goto err0; sa2->ai_family = sa->ai_family; sa2->ai_socktype = sa->ai_socktype; sa2->namelen = sa->namelen; /* Allocate and copy the sockaddr. */ if ((sa2->name = malloc(sa2->namelen)) == NULL) goto err1; memcpy(sa2->name, sa->name, sa2->namelen); /* Success! */ return (sa2); err1: free(sa2); err0: /* Failure! */ return (NULL); } /** * sock_addr_duplist(sas): * Duplicate the provided list of socket addresses. */ struct sock_addr ** sock_addr_duplist(struct sock_addr * const * sas) { struct sock_addr ** sas2; size_t i; /* Count socket addresses. */ for (i = 0; sas[i] != NULL; i++) continue; /* Allocate the list to hold addresses plus a NULL terminator. */ if ((sas2 = malloc((i + 1) * sizeof(struct sock_addr *))) == NULL) goto err0; /* Fill the list with NULLs to make error-path cleanup simpler. */ for (i = 0; sas[i] != NULL; i++) sas2[i] = NULL; sas2[i] = NULL; /* Duplicate addresses. */ for (i = 0; sas[i] != NULL; i++) { if ((sas2[i] = sock_addr_dup(sas[i])) == NULL) goto err1; } /* Success! */ return (sas2); err1: /* * Regardless of how many addresses we managed to duplicate before * failing and being sent here, we have a valid socket address list, * so we can free it and its constituent addresses easily. */ sock_addr_freelist(sas2); err0: /* Failure! */ return (NULL); } /** * sock_addr_serialize(sa, buf, buflen): * Allocate a buffer and serialize the socket address ${sa} into it. Return * the buffer via ${buf} and its length via ${buflen}. The serialization is * machine and operating system dependent. */ int sock_addr_serialize(const struct sock_addr * sa, uint8_t ** buf, size_t * buflen) { uint8_t * p; /* Compute buffer length and allocate buffer. */ *buflen = 2 * sizeof(int) + sizeof(socklen_t) + sa->namelen; if ((p = *buf = malloc(*buflen)) == NULL) goto err0; /* Copy in data. */ memcpy(p, &sa->ai_family, sizeof(int)); p += sizeof(int); memcpy(p, &sa->ai_socktype, sizeof(int)); p += sizeof(int); memcpy(p, &sa->namelen, sizeof(socklen_t)); p += sizeof(socklen_t); memcpy(p, sa->name, sa->namelen); /* Success! */ return (0); err0: /* Failure! */ return (-1); } /** * sock_addr_deserialize(buf, buflen): * Deserialize the ${buflen}-byte serialized socket address from ${buf}. */ struct sock_addr * sock_addr_deserialize(const uint8_t * buf, size_t buflen) { struct sock_addr * sa; /* Sanity check. */ if (buflen < 2 * sizeof(int) + sizeof(socklen_t)) goto err0; /* Allocate a structure and copy in fields. */ if ((sa = malloc(sizeof(struct sock_addr))) == NULL) goto err0; memcpy(&sa->ai_family, buf, sizeof(int)); buf += sizeof(int); memcpy(&sa->ai_socktype, buf, sizeof(int)); buf += sizeof(int); memcpy(&sa->namelen, buf, sizeof(socklen_t)); buf += sizeof(socklen_t); /* Allocate and copy the sockaddr. */ if (buflen != 2 * sizeof(int) + sizeof(socklen_t) + sa->namelen) goto err1; if ((sa->name = malloc(sa->namelen)) == NULL) goto err1; memcpy(sa->name, buf, sa->namelen); /* Success! */ return (sa); err1: free(sa); err0: /* Failure! */ return (NULL); } /* Prettyprint an IPv4 address. */ static char * prettyprint_ipv4(struct sockaddr_in * name) { char addr[INET_ADDRSTRLEN]; char * s; /* Convert IP address to string. */ if (inet_ntop(AF_INET, &name->sin_addr, addr, sizeof(addr)) == NULL) return (NULL); /* Construct address string. */ if (asprintf(&s, "[%s]:%d", addr, ntohs(name->sin_port)) == -1) return (NULL); /* Success! */ return (s); } /* Prettyprint an IPv6 address. */ static char * prettyprint_ipv6(struct sockaddr_in6 * name) { char addr[INET6_ADDRSTRLEN]; char * s; /* Convert IPv6 address to string. */ if (inet_ntop(AF_INET6, &name->sin6_addr, addr, sizeof(addr)) == NULL) return (NULL); /* Construct address string. */ if (asprintf(&s, "[%s]:%d", addr, ntohs(name->sin6_port)) == -1) return (NULL); /* Success! */ return (s); } /* Prettyprint a UNIX address. */ static char * prettyprint_unix(struct sockaddr_un * name) { /* Just strdup the path. */ return (strdup(name->sun_path)); } /** * sock_addr_prettyprint(sa): * Allocate and return a string in one of the forms * /path/to/unix/socket * [ip.v4.ad.dr]:port * [ipv6:add::ress]:port * representing the provided socket address. */ char * sock_addr_prettyprint(const struct sock_addr * sa) { /* Handle different types of addresses differently. */ switch (sa->ai_family) { case AF_INET: return (prettyprint_ipv4((struct sockaddr_in *)(sa->name))); case AF_INET6: return (prettyprint_ipv6((struct sockaddr_in6 *)(sa->name))); case AF_UNIX: return (prettyprint_unix((struct sockaddr_un *)(sa->name))); default: return (strdup("Unknown address")); } } spiped-1.3.1/lib/util/ctassert.h000644 001751 001751 00000000630 12132205630 020151 0ustar00cpercivacperciva000000 000000 #ifndef _CTASSERT_H_ #define _CTASSERT_H_ /* * CTASSERT(foo) will produce a compile-time error if "foo" is not a constant * expression which evaluates to a non-zero value. */ #ifndef CTASSERT #define CTASSERT(x) _CTASSERT(x, __LINE__) #define _CTASSERT(x, y) __CTASSERT(x, y) #define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1] #endif #endif /* !_CTASSERT_H_ */ spiped-1.3.1/lib/dnsthread/dnsthread.c000644 001751 001751 00000024664 12132205630 021304 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include #include "events.h" #include "noeintr.h" #include "sock.h" #include "warnp.h" #include "dnsthread.h" /* Thread management structure. */ struct dnsthread_internal { /* Threading glue. */ pthread_t thr; /* Thread ID. */ pthread_mutex_t mtx; /* Controls access to this structure. */ pthread_cond_t cv; /* Thread sleeps on this. */ /* State management. */ int state; /* THREAD_* as below. */ int wakeupsock[2]; /* Writes to [0], reads from [1]. */ /* Address resolution variables. */ char * addr; /* Address to be resolved. */ struct sock_addr ** sas; /* Results. */ int res_errno; /* Errno to be passed back on failure. */ /* Callback to occur when resolution is complete. */ int (*callback)(void *, struct sock_addr **); /* Callback. */ void * cookie; /* Cookie. */ }; /* Cookie used by dnsthread_resolve. */ struct resolve_cookie { int (*callback)(void *, struct sock_addr **); void * cookie; DNSTHREAD T; }; /* * Thread states. _resolveone moves the thread from SLEEPING to HASWORK; * workthread moves the thread from HASWORK to SLEEPING; and _kill moves the * thread from either state to SUICIDE. */ #define THREAD_SLEEPING 0 #define THREAD_HASWORK 1 #define THREAD_SUICIDE 2 /* Callback functions used below. */ static int callback_resolveone(void * cookie); static int callback_resolve(void *, struct sock_addr **); /* Address resolution thread. */ static void * workthread(void * cookie) { struct dnsthread_internal * T = cookie; char * addr; struct sock_addr ** sas; int res_errno = 0; int rc; uint8_t zero = 0; /* Grab the mutex. */ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) { warn0("pthread_mutex_lock: %s", strerror(rc)); exit(1); } /* Infinite loop doing work until told to suicide. */ do { /* * Sleep on the condition variable as long as we're in the * SLEEPING state. */ while (T->state == THREAD_SLEEPING) { /* Sleep until we're woken up. */ if ((rc = pthread_cond_wait(&T->cv, &T->mtx)) != 0) { warn0("pthread_cond_wait: %s", strerror(rc)); exit(1); } } /* If we need to kill ourself, stop looping. */ if (T->state == THREAD_SUICIDE) break; /* Grab the work. */ addr = T->addr; /* Release the mutex. */ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) { warn0("pthread_mutex_unlock: %s", strerror(rc)); exit(1); } /* Perform the address resolution. */ if ((sas = sock_resolve(addr)) == NULL) res_errno = errno; /* Grab the mutex again. */ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) { warn0("pthread_mutex_lock: %s", strerror(rc)); exit(1); } /* Write the answer back. */ T->sas = sas; T->res_errno = res_errno; /* Send a completion message. */ if (noeintr_write(T->wakeupsock[0], &zero, 1) != 1) { warnp("Error writing to wakeup socket"); exit(1); } /* Return to sleeping, unless we were instructed to die. */ if (T->state != THREAD_SUICIDE) T->state = THREAD_SLEEPING; } while (1); /* Close the socket pair. */ close(T->wakeupsock[1]); close(T->wakeupsock[0]); /* Destroy the condition variable. */ if ((rc = pthread_cond_destroy(&T->cv)) != 0) { warn0("pthread_cond_destroy: %s", strerror(rc)); exit(1); } /* Release the mutex. */ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) { warn0("pthread_mutex_unlock: %s", strerror(rc)); exit(1); } /* Destroy the mutex. */ if ((rc = pthread_mutex_destroy(&T->mtx)) != 0) { warn0("pthread_mutex_destroy: %s", strerror(rc)); exit(1); } /* Free the control structure. */ free(T); /* Successful thread termination. */ return (NULL); } /** * dnsthread_spawn(void): * Spawn a thread for performing address resolution. Return a token which can * be passed to dnsthread_resolveone and dnsthread_kill. */ DNSTHREAD dnsthread_spawn(void) { struct dnsthread_internal * T; int rc; /* Allocate a thread management structure. */ if ((T = malloc(sizeof(struct dnsthread_internal))) == NULL) goto err0; /* Create and lock a mutex. */ if ((rc = pthread_mutex_init(&T->mtx, NULL)) != 0) { warn0("pthread_mutex_init: %s", strerror(rc)); goto err1; } if ((rc = pthread_mutex_lock(&T->mtx)) != 0) { warn0("pthread_mutex_lock: %s", strerror(rc)); goto err2; } /* Create state-changed condition variable. */ if ((rc = pthread_cond_init(&T->cv, NULL)) != 0) { warn0("pthread_cond_init: %s", strerror(rc)); goto err3; } /* Create wakeup socketpair. */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, T->wakeupsock)) { warnp("socketpair"); goto err4; } /* The thread starts out sleeping. */ T->state = THREAD_SLEEPING; /* Create the thread. */ if ((rc = pthread_create(&T->thr, NULL, workthread, T)) != 0) { warn0("pthread_create: %s", strerror(rc)); goto err5; } /* Unlock the mutex. */ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) { warn0("pthread_mutex_unlock: %s", strerror(rc)); goto err0; } /* Success! */ return (T); err5: close(T->wakeupsock[1]); close(T->wakeupsock[0]); err4: pthread_cond_destroy(&T->cv); err3: pthread_mutex_unlock(&T->mtx); err2: pthread_mutex_destroy(&T->mtx); err1: free(T); err0: /* Failure! */ return (NULL); } /** * dnsthread_resolveone(T, addr, callback, cookie): * Using the thread for which ${T} was returned by dnsthread_spawn, resolve * the address ${addr}, which must be in one of the forms accepted by the * sock_resolve function. If ${T} is already resolving an address, do not * resolve this address and instead return with errno == EALREADY. Upon * completion, invoke ${callback}(${cookie}, sas), where ${sas} is a * NULL-terminated array of pointers to sock_addr structures or NULL on * resolution failure. */ int dnsthread_resolveone(DNSTHREAD T, const char * addr, int (* callback)(void *, struct sock_addr **), void * cookie) { int err = 0; int rc; /* Grab the mutex. */ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) { warn0("pthread_mutex_lock: %s", strerror(rc)); goto err0; } /* If the resolver is already busy, fail. */ if (T->state == THREAD_HASWORK) { err = EALREADY; goto ealready; } /* Duplicate the address to be resolved. */ if ((T->addr = strdup(addr)) == NULL) goto err1; /* Remember what callback we'll need to do eventually. */ T->callback = callback; T->cookie = cookie; /* There is now work for the thread to do. */ T->state = THREAD_HASWORK; /* Wake up the worker thread. */ if ((rc = pthread_cond_signal(&T->cv)) != 0) { warn0("pthread_cond_signal: %s", strerror(rc)); goto err1; } /* We want a callback when the worker thread pokes us. */ if (events_network_register(callback_resolveone, T, T->wakeupsock[1], EVENTS_NETWORK_OP_READ)) { warnp("Error registering wakeup listener"); goto err1; } ealready: /* Release the mutex. */ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) { warn0("pthread_mutex_unlock: %s", strerror(rc)); goto err0; } /* If err was set earlier, store the value in errno. */ if (err) errno = err; /* Success! */ return (0); err1: pthread_mutex_unlock(&T->mtx); err0: /* Failure! */ return (-1); } /* Callback for dnsthread_resolveone, from wakeup socket. */ static int callback_resolveone(void * cookie) { struct dnsthread_internal * T = cookie; struct sock_addr ** sas; uint8_t zero; int res_errno = 0; int (*callback)(void *, struct sock_addr **); void * cb_cookie; int rc; /* Drain the byte from the socketpair. */ if (read(T->wakeupsock[1], &zero, 1) != 1) { warn0("Error reading from wakeup socket"); goto err0; } /* Grab the mutex. */ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) { warn0("pthread_mutex_lock: %s", strerror(rc)); goto err0; } /* Free the (strduped) address which was to be resolved. */ free(T->addr); /* Grab the result. */ sas = T->sas; res_errno = T->res_errno; /* Grab the callback. */ callback = T->callback; cb_cookie = T->cookie; /* Release the mutex. */ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) { warn0("pthread_mutex_unlock: %s", strerror(rc)); goto err0; } /* Perform the callback. */ if (sas == NULL) errno = res_errno; return ((callback)(cb_cookie, sas)); err0: /* Failure! */ return (-1); } /** * dnsthread_kill(T): * Instruct an address resolution thread to die. If the thread does not have * an address resolution operation currently pending, wait for the thread to * die before returning. */ int dnsthread_kill(DNSTHREAD T) { int rc; int ostate; pthread_t thr; /* Lock the control structure. */ if ((rc = pthread_mutex_lock(&T->mtx)) != 0) { warn0("pthread_mutex_lock: %s", strerror(rc)); goto err0; } /* Remember what state the thread is currently in. */ ostate = T->state; /* Grab the thread ID. */ thr = T->thr; /* Tell the thread to die, and wake it up. */ T->state = THREAD_SUICIDE; if ((rc = pthread_cond_signal(&T->cv)) != 0) { warn0("pthread_cond_signal: %s", strerror(rc)); goto err1; } /* Unlock the control structure. */ if ((rc = pthread_mutex_unlock(&T->mtx)) != 0) { warn0("pthread_mutex_unlock: %s", strerror(rc)); goto err0; } /* If the thread was sleeping, wait for it to wake up and die. */ if (ostate == THREAD_SLEEPING) { if ((rc = pthread_join(thr, NULL)) != 0) { warn0("pthread_join: %s", strerror(rc)); goto err0; } } /* Success! */ return (0); err1: pthread_mutex_unlock(&T->mtx); err0: /* Failure! */ return (-1); } /** * dnsthread_resolve(addr, callback, cookie): * Perform a non-blocking address resolution of ${addr}. This function may * spawn a thread internally. */ int dnsthread_resolve(const char * addr, int (* callback)(void *, struct sock_addr **), void * cookie) { struct resolve_cookie * R; /* Bake a cookie. */ if ((R = malloc(sizeof(struct resolve_cookie))) == NULL) goto err0; R->callback = callback; R->cookie = cookie; /* Spawn a thread. */ if ((R->T = dnsthread_spawn()) == NULL) goto err1; /* Launch the request. */ if (dnsthread_resolveone(R->T, addr, callback_resolve, R)) goto err2; /* Success! */ return (0); err2: dnsthread_kill(R->T); err1: free(R); err0: /* Failure! */ return (-1); } /* Callback for dnsthread_resolve, from dnsthread_resolveone. */ static int callback_resolve(void * cookie, struct sock_addr ** sas) { struct resolve_cookie * R = cookie; int rc; /* Invoke the upstream callback. */ rc = (R->callback)(R->cookie, sas); /* Kill the resolver thread. */ if (dnsthread_kill(R->T)) rc = -1; /* Free our cookie. */ free(R); /* Return upstream return code or failure. */ return (rc); } spiped-1.3.1/lib/dnsthread/dnsthread.h000644 001751 001751 00000002667 12132205630 021310 0ustar00cpercivacperciva000000 000000 #ifndef _DNSTHREAD_H_ #define _DNSTHREAD_H_ /* Opaque address structure. */ struct sock_addr; /* Opaque thread token. */ typedef struct dnsthread_internal * DNSTHREAD; /** * dnsthread_spawn(void): * Spawn a thread for performing address resolution. Return a token which can * be passed to dnsthread_resolveone and dnsthread_kill. */ DNSTHREAD dnsthread_spawn(void); /** * dnsthread_resolveone(T, addr, callback, cookie): * Using the thread for which ${T} was returned by dnsthread_spawn, resolve * the address ${addr}, which must be in one of the forms accepted by the * sock_resolve function. If ${T} is already resolving an address, fail with * EALREADY. Upon completion, invoke ${callback}(${cookie}, sas), where * ${sas} is a NULL-terminated array of pointers to sock_addr structures or * NULL on resolution failure. */ int dnsthread_resolveone(DNSTHREAD, const char *, int (*)(void *, struct sock_addr **), void *); /** * dnsthread_kill(T): * Instruct an address resolution thread to die. If the thread does not have * an address resolution operation currently pending, wait for the thread to * die before returning. */ int dnsthread_kill(DNSTHREAD); /** * dnsthread_resolve(addr, callback, cookie): * Perform a non-blocking address resolution of ${addr}. This function may * spawn a thread internally. */ int dnsthread_resolve(const char *, int (*)(void *, struct sock_addr **), void *); #endif /* !_DNSTHREAD_H_ */ spiped-1.3.1/lib/network/network_buf.c000644 001751 001751 00000016663 12132205630 021372 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include #include #include #include "events.h" #include "warnp.h" #include "network.h" /** * We use three methods to prevent SIGPIPE from being sent, in order of * preference: * 1. The MSG_NOSIGNAL send(2) flag. * 2. The SO_NOSIGPIPE socket option. * 3. Blocking the SIGPIPE signal. */ #ifdef MSG_NOSIGNAL #define USE_MSG_NOSIGNAL #else /* !MSG_NOSIGNAL */ #define MSG_NOSIGNAL 0 #ifdef SO_NOSIGPIPE #define USE_SO_NOSIGPIPE #else /* !MSG_NOSIGNAL, !SO_NOSIGPIPE */ #define USE_SIGNAL #endif /* !MSG_NOSIGNAL, !SO_NOSIGPIPE */ #endif /* !MSG_NOSIGNAL */ struct network_buf_cookie { int (*callback)(void *, ssize_t); void * cookie; int fd; uint8_t * buf; size_t buflen; size_t minlen; size_t bufpos; ssize_t (* sendrecv)(int, void *, size_t, int); int op; int flags; }; static int docallback(struct network_buf_cookie *, size_t); static int callback_buf(void *); static struct network_buf_cookie * network_buf(int, uint8_t *, size_t, size_t, int (*)(void *, ssize_t), void *, ssize_t (*)(int, void *, size_t, int), int, int); static void cancel(void *); /* Invoke the callback, clean up, and return the callback's status. */ static int docallback(struct network_buf_cookie * C, size_t nbytes) { int rc; /* Invoke the callback. */ rc = (C->callback)(C->cookie, nbytes); /* Clean up. */ free(C); /* Return the callback's status. */ return (rc); } /* The socket is ready for reading/writing. */ static int callback_buf(void * cookie) { struct network_buf_cookie * C = cookie; size_t oplen; ssize_t len; #ifdef USE_SO_NOSIGPIPE int val; #endif #ifdef USE_SIGNAL void (*oldsig)(int); #endif /* Make sure we don't get a SIGPIPE. */ #ifdef USE_SO_NOSIGPIPE val = 1; if (setsockopt(C->fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(int))) { warnp("setsockopt(SO_NOSIGPIPE)"); goto failed; } #endif #ifdef USE_SIGNAL if ((oldsig = signal(SIGPIPE, SIG_IGN)) == SIG_ERR) { warnp("signal(SIGPIPE)"); goto failed; } #endif /* Attempt to read/write data to/from the buffer. */ oplen = C->buflen - C->bufpos; len = (C->sendrecv)(C->fd, C->buf + C->bufpos, oplen, C->flags); /* Undo whatever we did to prevent SIGPIPEs. */ #ifdef USE_SO_NOSIGPIPE val = 0; if (setsockopt(C->fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(int))) { warnp("setsockopt(SO_NOSIGPIPE)"); goto failed; } #endif #ifdef USE_SIGNAL if (signal(SIGPIPE, oldsig) == SIG_ERR) { warnp("signal(SIGPIPE)"); goto failed; } #endif /* Failure? */ if (len == -1) { /* Was it really an error, or just a try-again? */ if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR)) goto tryagain; /* Something went wrong. */ goto failed; } else if (len == 0) { /* The socket was shut down by the remote host. */ goto eof; } /* We processed some data. Do we need to keep going? */ if ((C->bufpos += len) < C->minlen) goto tryagain; /* Invoke the callback and return. */ return (docallback(C, C->bufpos)); tryagain: /* Reset the event. */ if (events_network_register(callback_buf, C, C->fd, C->op)) goto failed; /* Callback was reset. */ return (0); eof: /* Sanity-check: This should only occur for reads. */ assert(C->op == EVENTS_NETWORK_OP_READ); /* Invoke the callback with an EOF status and return. */ return (docallback(C, 0)); failed: /* Invoke the callback with a failure status and return. */ return (docallback(C, -1)); } /** * network_buf(fd, buf, buflen, minlen, callback, cookie, sendrecv, op, flags): * Asynchronously read/write up to ${buflen} bytes of data from/to ${fd} * to/from ${buf}. When at least ${minlen} bytes have been read/written, * invoke ${callback}(${cookie}, nbytes), where nbytes is 0 on EOF or -1 on * error and the number of bytes read/written (between ${minlen} and ${buflen} * inclusive) otherwise. Return a cookie which can be passed to buf_cancel * in order to cancel the read/write. */ static struct network_buf_cookie * network_buf(int fd, uint8_t * buf, size_t buflen, size_t minlen, int (* callback)(void *, ssize_t), void * cookie, ssize_t (* sendrecv)(int, void *, size_t, int), int op, int flags) { struct network_buf_cookie * C; /* Sanity-check: # bytes must fit into a ssize_t. */ assert(buflen <= SSIZE_MAX); /* Bake a cookie. */ if ((C = malloc(sizeof(struct network_buf_cookie))) == NULL) goto err0; C->callback = callback; C->cookie = cookie; C->fd = fd; C->buf = buf; C->buflen = buflen; C->minlen = minlen; C->bufpos = 0; C->sendrecv = sendrecv; C->op = op; C->flags = flags; /* Register a callback for network readiness. */ if (events_network_register(callback_buf, C, C->fd, C->op)) goto err1; /* Success! */ return (C); err1: free(C); err0: /* Failure! */ return (NULL); } /* Cancel the read/write. */ static void cancel(void * cookie) { struct network_buf_cookie * C = cookie; /* Kill the network event. */ events_network_cancel(C->fd, C->op); /* Free the cookie. */ free(C); } /** * network_read(fd, buf, buflen, minread, callback, cookie): * Asynchronously read up to ${buflen} bytes of data from ${fd} into ${buf}. * When at least ${minread} bytes have been read or on error, invoke * ${callback}(${cookie}, lenread), where lenread is 0 on EOF or -1 on error, * and the number of bytes read (between ${minread} and ${buflen} inclusive) * otherwise. Return a cookie which can be passed to network_read_cancel in * order to cancel the read. */ void * network_read(int fd, uint8_t * buf, size_t buflen, size_t minread, int (* callback)(void *, ssize_t), void * cookie) { /* Make sure buflen is non-zero. */ if (buflen == 0) { warn0("Programmer error: Cannot read zero-byte buffer"); return (NULL); } /* Get network_buf to set things up for us. */ return (network_buf(fd, buf, buflen, minread, callback, cookie, recv, EVENTS_NETWORK_OP_READ, 0)); } /** * network_read_cancel(cookie): * Cancel the buffer read for which the cookie ${cookie} was returned by * network_read. Do not invoke the callback associated with the read. */ void network_read_cancel(void * cookie) { /* Get cancel to do the work for us. */ cancel(cookie); } /** * network_write(fd, buf, buflen, minwrite, callback, cookie): * Asynchronously write up to ${buflen} bytes of data from ${buf} to ${fd}. * When at least ${minwrite} bytes have been written or on error, invoke * ${callback}(${cookie}, lenwrit), where lenwrit is -1 on error and the * number of bytes written (between ${minwrite} and ${buflen} inclusive) * otherwise. Return a cookie which can be passed to network_write_cancel in * order to cancel the write. */ void * network_write(int fd, const uint8_t * buf, size_t buflen, size_t minwrite, int (* callback)(void *, ssize_t), void * cookie) { /* Make sure buflen is non-zero. */ if (buflen == 0) { warn0("Programmer error: Cannot write zero-byte buffer"); return (NULL); } /* Get network_buf to set things up for us. */ return (network_buf(fd, (uint8_t *)(uintptr_t)buf, buflen, minwrite, callback, cookie, (ssize_t (*)(int, void *, size_t, int))send, EVENTS_NETWORK_OP_WRITE, MSG_NOSIGNAL)); } /** * network_write_cancel(cookie): * Cancel the buffer write for which the cookie ${cookie} was returned by * network_write. Do not invoke the callback associated with the write. */ void network_write_cancel(void * cookie) { /* Get cancel to do the work for us. */ cancel(cookie); } spiped-1.3.1/lib/network/network_accept.c000644 001751 001751 00000004465 12132205630 022052 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include "events.h" #include "network.h" struct accept_cookie { int (* callback)(void *, int); void * cookie; int fd; }; /* Accept the connection and invoke the callback. */ static int callback_accept(void * cookie) { struct accept_cookie * C = cookie; int s; int rc; /* Attempt to accept a new connection. */ if ((s = accept(C->fd, NULL, NULL)) == -1) { /* If a connection isn't available, reset the callback. */ if ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == ECONNABORTED) || (errno == EINTR)) goto tryagain; } /* Call the upstream callback. */ rc = (C->callback)(C->cookie, s); /* Free the cookie. */ free(C); /* Return status from upstream callback. */ return (rc); tryagain: /* Reset the callback. */ return (events_network_register(callback_accept, C, C->fd, EVENTS_NETWORK_OP_READ)); } /** * network_accept(fd, callback, cookie): * Asynchronously accept a connection on the socket ${fd}, which must be * already marked as listening and non-blocking. When a connection has been * accepted or an error occurs, invoke ${callback}(${cookie}, s) where s is * the accepted connection or -1 on error. Return a cookie which can be * passed to network_accept_cancel in order to cancel the accept. */ void * network_accept(int fd, int (* callback)(void *, int), void * cookie) { struct accept_cookie * C; /* Bake a cookie. */ if ((C = malloc(sizeof(struct accept_cookie))) == NULL) goto err0; C->callback = callback; C->cookie = cookie; C->fd = fd; /* * Register a network event. A connection arriving on a listening * socket is treated by select(2) as the socket becoming readable. */ if (events_network_register(callback_accept, C, C->fd, EVENTS_NETWORK_OP_READ)) goto err1; /* Success! */ return (C); err1: free(C); err0: /* Failure! */ return (NULL); } /** * network_accept_cancel(cookie); * Cancel the connection accept for which the cookie ${cookie} was returned * by network_accept. Do not invoke the callback associated with the accept. */ void network_accept_cancel(void * cookie) { struct accept_cookie * C = cookie; /* Cancel the network event. */ events_network_cancel(C->fd, EVENTS_NETWORK_OP_READ); /* Free the cookie. */ free(C); } spiped-1.3.1/lib/network/network.h000644 001751 001751 00000006170 12132205630 020533 0ustar00cpercivacperciva000000 000000 #ifndef _NETWORK_H_ #define _NETWORK_H_ #include #include #include #include "sock.h" /** * network_accept(fd, callback, cookie): * Asynchronously accept a connection on the socket ${fd}, which must be * already marked as listening and non-blocking. When a connection has been * accepted or an error occurs, invoke ${callback}(${cookie}, s) where s is * the accepted connection or -1 on error. Return a cookie which can be * passed to network_accept_cancel in order to cancel the accept. */ void * network_accept(int, int (*)(void *, int), void *); /** * network_accept_cancel(cookie); * Cancel the connection accept for which the cookie ${cookie} was returned * by network_accept. Do not invoke the callback associated with the accept. */ void network_accept_cancel(void *); /** * network_connect(sas, callback, cookie): * Iterate through the addresses in ${sas}, attempting to create and connect * a non-blocking socket. Once connected, invoke ${callback}(${cookie}, s) * where s is the connected socket; upon fatal error or if there are no * addresses remaining to attempt, invoke ${callback}(${cookie}, -1). Return * a cookie which can be passed to network_connect_cancel in order to cancel * the connection attempt. */ void * network_connect(struct sock_addr * const *, int (*)(void *, int), void *); /** * network_connect_cancel(cookie): * Cancel the connection attempt for which ${cookie} was returned by * network_connect. Do not invoke the associated callback. */ void network_connect_cancel(void *); /** * network_read(fd, buf, buflen, minread, callback, cookie): * Asynchronously read up to ${buflen} bytes of data from ${fd} into ${buf}. * When at least ${minread} bytes have been read or on error, invoke * ${callback}(${cookie}, lenread), where lenread is 0 on EOF or -1 on error, * and the number of bytes read (between ${minread} and ${buflen} inclusive) * otherwise. Return a cookie which can be passed to network_read_cancel in * order to cancel the read. */ void * network_read(int, uint8_t *, size_t, size_t, int (*)(void *, ssize_t), void *); /** * network_read_cancel(cookie): * Cancel the buffer read for which the cookie ${cookie} was returned by * network_read. Do not invoke the callback associated with the read. */ void network_read_cancel(void *); /** * network_write(fd, buf, buflen, minwrite, callback, cookie): * Asynchronously write up to ${buflen} bytes of data from ${buf} to ${fd}. * When at least ${minwrite} bytes have been written or on error, invoke * ${callback}(${cookie}, lenwrit), where lenwrit is -1 on error and the * number of bytes written (between ${minwrite} and ${buflen} inclusive) * otherwise. Return a cookie which can be passed to network_write_cancel in * order to cancel the write. */ void * network_write(int, const uint8_t *, size_t, size_t, int (*)(void *, ssize_t), void *); /** * network_write_cancel(cookie): * Cancel the buffer write for which the cookie ${cookie} was returned by * network_write. Do not invoke the callback associated with the write. */ void network_write_cancel(void *); #endif /* !_NETWORK_H_ */ spiped-1.3.1/lib/network/network_connect.c000644 001751 001751 00000007716 12132205630 022246 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include "events.h" #include "sock.h" #include "network.h" struct connect_cookie { int (* callback)(void *, int); void * cookie; struct sock_addr * const * sas; void * cookie_immediate; int s; }; static int tryconnect(struct connect_cookie *); /* Invoke the upstream callback and clean up. */ static int docallback(void * cookie) { struct connect_cookie * C = cookie; int rc; /* Invoke the upstream callback. */ rc = (C->callback)(C->cookie, C->s); /* Free the cookie. */ free(C); /* Return status from upstream callback. */ return (rc); } /* Callback when connect(2) succeeds or fails. */ static int callback_connect(void * cookie) { struct connect_cookie * C = cookie; int sockerr; socklen_t sockerrlen = sizeof(int); /* Did we succeed? */ if (getsockopt(C->s, SOL_SOCKET, SO_ERROR, &sockerr, &sockerrlen)) goto err1; if (sockerr != 0) goto failed; /* * Perform the callback (this can be done here rather than being * scheduled as an immediate callback, as we're already running from * callback context). */ return (docallback(C)); failed: /* Close the socket which failed to connect. */ close(C->s); /* We don't have an open socket any more. */ C->s = -1; /* This address didn't work. */ C->sas++; /* Try other addresses until we run out of options. */ return (tryconnect(C)); err1: close(C->s); free(C); /* Fatal error! */ return (-1); } /* Try to launch a connection. Free the cookie on fatal errors. */ static int tryconnect(struct connect_cookie * C) { /* Try addresses until we find one which doesn't fail immediately. */ for (; C->sas[0] != NULL; C->sas++) { /* Can we try to connect to this address? */ if ((C->s = sock_connect_nb(C->sas[0])) != -1) break; } /* Did we run out of addresses to try? */ if (C->sas[0] == NULL) goto failed; /* Wait until this socket connects or fails to do so. */ if (events_network_register(callback_connect, C, C->s, EVENTS_NETWORK_OP_WRITE)) goto err1; /* Success! */ return (0); failed: /* Schedule a callback. */ if ((C->cookie_immediate = events_immediate_register(docallback, C, 0)) == NULL) goto err1; /* Failure successfully handled. */ return (0); err1: if (C->s != -1) close(C->s); free(C); /* Fatal error. */ return (-1); } /** * network_connect(sas, callback, cookie): * Iterate through the addresses in ${sas}, attempting to create and connect * a non-blocking socket. Once connected, invoke ${callback}(${cookie}, s) * where s is the connected socket; upon fatal error or if there are no * addresses remaining to attempt, invoke ${callback}(${cookie}, -1). Return * a cookie which can be passed to network_connect_cancel in order to cancel * the connection attempt. */ void * network_connect(struct sock_addr * const * sas, int (* callback)(void *, int), void * cookie) { struct connect_cookie * C; /* Bake a cookie. */ if ((C = malloc(sizeof(struct connect_cookie))) == NULL) goto err0; C->callback = callback; C->cookie = cookie; C->sas = sas; C->cookie_immediate = NULL; C->s = -1; /* Try to connect to the first address. */ if (tryconnect(C)) goto err0; /* Success! */ return (C); err0: /* Failure! */ return (NULL); } /** * network_connect_cancel(cookie): * Cancel the connection attempt for which ${cookie} was returned by * network_connect. Do not invoke the associated callback. */ void network_connect_cancel(void * cookie) { struct connect_cookie * C = cookie; /* We should have either an immediate callback or a socket. */ assert((C->cookie_immediate != NULL) || (C->s != -1)); assert((C->cookie_immediate == NULL) || (C->s == -1)); /* Cancel any immediate callback. */ if (C->cookie_immediate != NULL) events_immediate_cancel(C->cookie_immediate); /* Close any socket. */ if (C->s != -1) { events_network_cancel(C->s, EVENTS_NETWORK_OP_WRITE); close(C->s); } /* Free the cookie. */ free(C); } spiped-1.3.1/POSIX/posix-l.c000644 001751 001751 00000000027 12132205630 017066 0ustar00cpercivacperciva000000 000000 int main() {return 0;} spiped-1.3.1/POSIX/README000644 001751 001751 00000000775 12132205630 016221 0ustar00cpercivacperciva000000 000000 POSIX compatibility code ------------------------ This code exists to work around some common POSIX compatibility issues. POSIX specifies that if the first line of a Makefile is ".POSIX:" then the Makefile should be processed according to POSIX rules, including with CC=c99. Further, c99 is required to understand the -lrt and -lxnet options (and ignore them if the routines they specify linkage for are already in the standard C library). Unfortunately some systems fail or one or both of these accounts. spiped-1.3.1/POSIX/posix-l.sh000755 001751 001751 00000000545 12132205630 017266 0ustar00cpercivacperciva000000 000000 # Should be sourced by `command -p sh posix-l.sh` from within a Makefile. FIRST=YES for LIB in rt xnet; do if ${CC} -l${LIB} posix-l.c 2>/dev/null; then if [ ${FIRST} = "NO" ]; then printf " "; fi printf "%s" "-l${LIB}"; FIRST=NO; else echo "WARNING: POSIX violation: make's CC doesn't understand -l${LIB}" >/dev/stderr fi rm -f a.out done spiped-1.3.1/spipe/pushbits.h000644 001751 001751 00000000270 12132205630 017557 0ustar00cpercivacperciva000000 000000 #ifndef _PUSHBITS_H_ #define _PUSHBITS_H_ /** * pushbits(in, out): * Create a thread which copies data from ${in} to ${out}. */ int pushbits(int, int); #endif /* !_PUSHBITS_H_ */ spiped-1.3.1/spipe/README000644 001751 001751 00000001252 12132205630 016426 0ustar00cpercivacperciva000000 000000 spipe usage =========== usage: spipe -t -k [-fj] [-o ] Options: -t Address to which spipe should connect. -k Use the provided key file to authenticate and encrypt. -f Use fast/weak handshaking: This reduces the CPU time spent in the initial connection setup, at the expense of losing perfect forward secrecy. -j Disable transport layer keep-alives. (By default they are enabled.) -o Timeout, in seconds, after which an attempt to connect to the target or a protocol handshake will be aborted (and the connection dropped) if not completed. Defaults to 5s. spiped-1.3.1/spipe/spipe.1000644 001751 001751 00000004162 12132205630 016753 0ustar00cpercivacperciva000000 000000 .\"- .\" Copyright (c) 2012 Andreas Olsson .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .TH SPIPE 1 "April 2, 2013" "spiped 1.3.0" "spipe README" .SH NAME spipe \- spiped client utility .SH SYNOPSIS .B spipe \-t \-k [\-fj] [\-o ] .SH OPTIONS .TP .B \-t Address to which spipe should connect. .TP .B \-k Use the provided key file to authenticate and encrypt. .TP .B \-f Use fast/weak handshaking: This reduces the CPU time spent in the initial connection setup, at the expense of losing perfect forward secrecy. .TP .B \-j Disable transport layer keep-alives. (By default they are enabled.) .TP .B \-o Timeout, in seconds, after which an attempt to connect to the target or a protocol handshake will be aborted (and the connection dropped) if not completed. Defaults to 5s. .SH SEE ALSO .BR spiped (1). spiped-1.3.1/spipe/pushbits.c000644 001751 001751 00000003300 12132205630 017547 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include #include "noeintr.h" #include "warnp.h" #include "pushbits.h" struct push { uint8_t buf[BUFSIZ]; int in; int out; }; /* Bit-pushing thread. */ static void * workthread(void * cookie) { struct push * P = cookie; ssize_t readlen; /* Infinite loop unless we hit EOF or an error. */ do { /* Read data and die on error. */ if ((readlen = read(P->in, P->buf, BUFSIZ)) == -1) { if (errno == EINTR) continue; warnp("Error reading"); exit(1); } /* If we hit EOF, exit the loop. */ if (readlen == 0) break; /* Write the data back out. */ if (noeintr_write(P->out, &P->buf, readlen) != readlen) { warnp("Error writing"); exit(1); } } while (1); /* Close the descriptor we hit EOF on. */ close(P->in); /* * Try to shut down the descriptor we're writing to. Ignore ENOTSOCK, * since it might, indeed, not be a socket. */ if (shutdown(P->out, SHUT_WR)) { if (errno != ENOTSOCK) { warnp("Error shutting down socket"); exit(1); } } /* Free our parameters. */ free(P); /* We're done. */ return (NULL); } /** * pushbits(in, out): * Create a thread which copies data from ${in} to ${out}. */ int pushbits(int in, int out) { struct push * P; pthread_t thr; int rc; /* Allocate structure. */ if ((P = malloc(sizeof(struct push))) == NULL) goto err0; P->in = in; P->out = out; /* Create thread. */ if ((rc = pthread_create(&thr, NULL, workthread, P)) != 0) { warn0("pthread_create: %s", strerror(rc)); goto err1; } /* Success! */ return (0); err1: free(P); err0: /* Failure! */ return (-1); } spiped-1.3.1/spipe/main.c000644 001751 001751 00000006342 12132205630 016643 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include #include "asprintf.h" #include "events.h" #include "sha256.h" #include "sock.h" #include "warnp.h" #include "proto_conn.h" #include "proto_crypt.h" #include "pushbits.h" static int callback_conndied(void * cookie) { (void)cookie; /* UNUSED */ /* We're done! */ exit(0); } static void usage(void) { fprintf(stderr, "usage: spipe -t -k " " [-fj] [-o ]\n"); exit(1); } /* Simplify error-handling in command-line parse loop. */ #define OPT_EPARSE(opt, arg) do { \ warnp("Error parsing argument: -%c %s", opt, arg); \ exit(1); \ } while (0) int main(int argc, char * argv[]) { /* Command-line parameters. */ int opt_f = 0; int opt_j = 0; const char * opt_k = NULL; double opt_o = 0.0; const char * opt_t = NULL; /* Working variables. */ struct sock_addr ** sas_t; struct proto_secret * K; int ch; int s[2]; WARNP_INIT; /* Parse the command line. */ while ((ch = getopt(argc, argv, "fjk:o:t:")) != -1) { switch (ch) { case 'f': if (opt_f) usage(); opt_f = 1; break; case 'j': if (opt_j) usage(); opt_j = 1; break; case 'k': if (opt_k) usage(); opt_k = optarg; break; case 'o': if (opt_o != 0.0) usage(); if ((opt_o = strtod(optarg, NULL)) == 0.0) { warn0("Invalid option: -o %s", optarg); exit(1); } break; case 't': if (opt_t) usage(); opt_t = optarg; break; default: usage(); } } /* We should have processed all the arguments. */ if (argc != optind) usage(); /* Set defaults. */ if (opt_o == 0.0) opt_o = 5.0; /* Sanity-check options. */ if (opt_k == NULL) usage(); if (!(opt_o > 0.0)) usage(); if (opt_t == NULL) usage(); /* Resolve target address. */ if ((sas_t = sock_resolve(opt_t)) == NULL) { warnp("Error resolving socket address: %s", opt_t); exit(1); } if (sas_t[0] == NULL) { warn0("No addresses found for %s", opt_t); exit(1); } /* Load the keying data. */ if ((K = proto_crypt_secret(opt_k)) == NULL) { warnp("Error reading shared secret"); exit(1); } /* * Create a socket pair to push bits through. The spiped protocol * code expects to be handed a socket to read/write bits to, and our * stdin/stdout might not be sockets (in fact, almost certainly aren't * sockets); so we'll hand one end of the socket pair to the spiped * protocol code and shuttle bits between stdin/stdout and the other * end of the socket pair ourselves. */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, s)) { warnp("socketpair"); exit(1); } /* Set up a connection. */ if (proto_conn_create(s[1], sas_t, 0, opt_f, opt_j, K, opt_o, callback_conndied, NULL)) { warnp("Could not set up connection"); exit(1); } /* Push bits from stdin into the socket. */ if (pushbits(STDIN_FILENO, s[0]) || pushbits(s[0], STDOUT_FILENO)) { warnp("Could not push bits"); exit(1); } /* Loop until we die. */ do { if (events_run()) { warnp("Error running event loop"); exit(1); } } while(1); /* NOTREACHED */ /* * If we could reach this point, we would free memory, close sockets, * and otherwise clean up here. */ } spiped-1.3.1/spipe/Makefile000644 001751 001751 00000011434 12132206320 017206 0ustar00cpercivacperciva000000 000000 .POSIX: PROG=spipe MAN1=spipe.1 SRCS=main.c pushbits.c proto_conn.c proto_crypt.c proto_handshake.c proto_pipe.c sha256.c elasticarray.c ptrheap.c timerqueue.c asprintf.c entropy.c monoclock.c noeintr.c sock.c warnp.c events_immediate.c events_network.c events_timer.c events.c network_buf.c network_connect.c crypto_aesctr.c crypto_dh.c crypto_dh_group14.c crypto_entropy.c crypto_verify_bytes.c IDIRS=-I ../proto -I ../lib/alg -I ../lib/datastruct -I ../lib/util -I ../lib/events -I ../lib/network -I ../lib/crypto LDADD_REQ=-lcrypto -lpthread all: ${PROG} install:${PROG} mkdir -p ${BINDIR} cp ${PROG} ${BINDIR}/_inst.${PROG}.$$$$_ && \ strip ${BINDIR}/_inst.${PROG}.$$$$_ && \ chmod 0555 ${BINDIR}/_inst.${PROG}.$$$$_ && \ mv -f ${BINDIR}/_inst.${PROG}.$$$$_ ${BINDIR}/${PROG} if ! [ -z "${MAN1DIR}" ]; then \ for MPAGE in ${MAN1}; do \ cp $$MPAGE ${MAN1DIR}/_inst.$$MPAGE.$$$$_ && \ chmod 0444 ${MAN1DIR}/_inst.$$MPAGE.$$$$_ && \ mv -f ${MAN1DIR}/_inst.$$MPAGE.$$$$_ ${MAN1DIR}/$$MPAGE; \ done; \ fi clean: rm -f ${PROG} ${SRCS:.c=.o} ${PROG}:${SRCS:.c=.o} ${CC} -o ${PROG} ${SRCS:.c=.o} ${LDADD_EXTRA} ${LDADD_REQ} ${LDADD_POSIX} main.o: main.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c main.c -o main.o pushbits.o: pushbits.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c pushbits.c -o pushbits.o proto_conn.o: ../proto/proto_conn.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../proto/proto_conn.c -o proto_conn.o proto_crypt.o: ../proto/proto_crypt.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../proto/proto_crypt.c -o proto_crypt.o proto_handshake.o: ../proto/proto_handshake.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../proto/proto_handshake.c -o proto_handshake.o proto_pipe.o: ../proto/proto_pipe.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../proto/proto_pipe.c -o proto_pipe.o sha256.o: ../lib/alg/sha256.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/alg/sha256.c -o sha256.o elasticarray.o: ../lib/datastruct/elasticarray.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/datastruct/elasticarray.c -o elasticarray.o ptrheap.o: ../lib/datastruct/ptrheap.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/datastruct/ptrheap.c -o ptrheap.o timerqueue.o: ../lib/datastruct/timerqueue.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/datastruct/timerqueue.c -o timerqueue.o asprintf.o: ../lib/util/asprintf.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/asprintf.c -o asprintf.o entropy.o: ../lib/util/entropy.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/entropy.c -o entropy.o monoclock.o: ../lib/util/monoclock.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/monoclock.c -o monoclock.o noeintr.o: ../lib/util/noeintr.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/noeintr.c -o noeintr.o sock.o: ../lib/util/sock.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/sock.c -o sock.o warnp.o: ../lib/util/warnp.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/warnp.c -o warnp.o events_immediate.o: ../lib/events/events_immediate.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/events/events_immediate.c -o events_immediate.o events_network.o: ../lib/events/events_network.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/events/events_network.c -o events_network.o events_timer.o: ../lib/events/events_timer.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/events/events_timer.c -o events_timer.o events.o: ../lib/events/events.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/events/events.c -o events.o network_buf.o: ../lib/network/network_buf.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/network/network_buf.c -o network_buf.o network_connect.o: ../lib/network/network_connect.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/network/network_connect.c -o network_connect.o crypto_aesctr.o: ../lib/crypto/crypto_aesctr.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/crypto/crypto_aesctr.c -o crypto_aesctr.o crypto_dh.o: ../lib/crypto/crypto_dh.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/crypto/crypto_dh.c -o crypto_dh.o crypto_dh_group14.o: ../lib/crypto/crypto_dh_group14.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/crypto/crypto_dh_group14.c -o crypto_dh_group14.o crypto_entropy.o: ../lib/crypto/crypto_entropy.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/crypto/crypto_entropy.c -o crypto_entropy.o crypto_verify_bytes.o: ../lib/crypto/crypto_verify_bytes.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/crypto/crypto_verify_bytes.c -o crypto_verify_bytes.o spiped-1.3.1/spiped/README000644 001751 001751 00000004512 12132205630 016574 0ustar00cpercivacperciva000000 000000 spiped usage ============ usage: spiped {-e | -d} -s -t -k [-DfFj] [-n ] [-o ] [-p ] [{-r | -R}] Options: -e Take unencrypted connections from the source socket and send encrypted connections to the target socket. -d Take encrypted connections from the source socket and send unencrypted connections to the target socket. -s Address on which spiped should listen for incoming connections. Must be in one of the following formats: /absolute/path/to/unix/socket host.name:port [ip.v4.ad.dr]:port [ipv6::addr]:port Note that hostnames are resolved when spiped is launched and are not re-resolved later; thus if DNS entries change spiped will continue to connect to the expired address. -t Address to which spiped should connect. -k Use the provided key file to authenticate and encrypt. -D Wait for DNS. Normally when spiped is launched it resolves addresses and binds to its source socket before the parent process returns; with this option it will daemonize first and retry failed DNS lookups until they succeed. This allows spiped to launch even if DNS isn't set up yet, but at the expense of losing the guarantee that once spiped has finished launching it will be ready to create pipes. -f Use fast/weak handshaking: This reduces the CPU time spent in the initial connection setup, at the expense of losing perfect forward secrecy. -F Run in foreground. This can be useful with systems like daemontools. -j Disable transport layer keep-alives. (By default they are enabled.) -n Limit on the number of simultaneous connections allowed. Defaults to 100 connections. -o Timeout, in seconds, after which an attempt to connect to the target or a protocol handshake will be aborted (and the connection dropped) if not completed. Defaults to 5s. -p File to which spiped's process ID should be written. Defaults to .pid (in the current directory if is not an absolute path). -r Re-resolve the address of every seconds. Defaults to re-resolution every 60 seconds. -R Do not re-resolve the address of . spiped-1.3.1/spiped/dispatch.c000644 001751 001751 00000011171 12132205630 017656 0ustar00cpercivacperciva000000 000000 #include #include #include #include "dnsthread.h" #include "events.h" #include "network.h" #include "sock.h" #include "sock_util.h" #include "warnp.h" #include "proto_conn.h" #include "dispatch.h" struct accept_state { int s; const char * tgt; struct sock_addr ** sas; double rtime; int decr; int nofps; int nokeepalive; const struct proto_secret * K; size_t nconn; size_t nconn_max; double timeo; void * accept_cookie; DNSTHREAD T; }; static int callback_gotconn(void *, int); static int callback_resolveagain(void *); /* Callback from address resolution. */ static int callback_resolve(void * cookie, struct sock_addr ** sas) { struct accept_state * A = cookie; /* If the address resolution succeeded... */ if (sas != NULL) { /* Free the old addresses. */ sock_addr_freelist(A->sas); /* Use the new addresses. */ A->sas = sas; } /* Wait a while before resolving again. */ if (events_timer_register_double(callback_resolveagain, A, A->rtime) == NULL) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); } /* Timer callback to trigger another address resolution. */ static int callback_resolveagain(void * cookie) { struct accept_state * A = cookie; /* Re-resolve the target address. */ return (dnsthread_resolveone(A->T, A->tgt, callback_resolve, A)); } /* Non-blocking accept, if we can have more connections. */ static int doaccept(struct accept_state * A) { int rc = 0; /* If we can, accept a new connection. */ if ((A->nconn < A->nconn_max) && (A->accept_cookie == NULL)) { if ((A->accept_cookie = network_accept(A->s, callback_gotconn, A)) == NULL) rc = -1; } /* Return success/fail status. */ return (rc); } /* A connection has closed. Accept more if necessary. */ static int callback_conndied(void * cookie) { struct accept_state * A = cookie; /* We've lost a connection. */ A->nconn -= 1; /* Maybe accept more connections. */ return (doaccept(A)); } /* Handle an incoming connection. */ static int callback_gotconn(void * cookie, int s) { struct accept_state * A = cookie; struct sock_addr ** sas; /* This accept is no longer in progress. */ A->accept_cookie = NULL; /* If we got a -1 descriptor, something went seriously wrong. */ if (s == -1) { warnp("network_accept failed"); goto err0; } /* We have gained a connection. */ A->nconn += 1; /* Duplicate the target address list. */ if ((sas = sock_addr_duplist(A->sas)) == NULL) goto err1; /* Create a new connection. */ if (proto_conn_create(s, sas, A->decr, A->nofps, A->nokeepalive, A->K, A->timeo, callback_conndied, A)) { warnp("Failure setting up new connection"); goto err2; } /* Accept another connection if we can. */ if (doaccept(A)) goto err0; /* Success! */ return (0); err2: sock_addr_freelist(sas); err1: A->nconn -= 1; close(s); err0: /* Failure! */ return (-1); } /** * dispatch_accept(s, tgt, rtime, sas, decr, nofps, nokeepalive, K, nconn_max, * timeo): * Start accepting connections on the socket ${s}. Connect to the target * ${tgt}, re-resolving it every ${rtime} seconds if ${rtime} > 0; on address * resolution failure use the most recent successfully obtained addresses, or * the addresses ${sas}. If ${decr} is 0, encrypt the outgoing connections; if * ${decr} is non-zero, decrypt the incoming connections. Don't accept more * than ${nconn_max} connections. If ${nofps} is non-zero, don't use perfect * forward secrecy. Enable transport layer keep-alives (if applicable) if and * only if ${nokeepalive} is zero. Drop connections if the handshake or * connecting to the target takes more than ${timeo} seconds. */ int dispatch_accept(int s, const char * tgt, double rtime, struct sock_addr ** sas, int decr, int nofps, int nokeepalive, const struct proto_secret * K, size_t nconn_max, double timeo) { struct accept_state * A; /* Bake a cookie. */ if ((A = malloc(sizeof(struct accept_state))) == NULL) goto err0; A->s = s; A->tgt = tgt; A->sas = sas; A->rtime = rtime; A->decr = decr; A->nofps = nofps; A->nokeepalive = nokeepalive; A->K = K; A->nconn = 0; A->nconn_max = nconn_max; A->timeo = timeo; A->accept_cookie = NULL; /* If address re-resolution is enabled... */ if (rtime > 0.0) { /* Launch an address resolution thread. */ A->T = dnsthread_spawn(); /* Re-resolve the target address after a while. */ if (events_timer_register_double(callback_resolveagain, A, A->rtime) == NULL) goto err1; } /* Accept a connection. */ if (doaccept(A)) goto err1; /* Success! */ return (0); err1: if (rtime > 0.0) dnsthread_kill(A->T); free(A); err0: /* Failure! */ return (-1); } spiped-1.3.1/spiped/spiped.1000644 001751 001751 00000007413 12132205630 017265 0ustar00cpercivacperciva000000 000000 .\"- .\" Copyright (c) 2012 Andreas Olsson .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .TH SPIPED 1 "April 2, 2013" "spiped 1.3.0" "spiped README" .SH NAME spiped \- secure pipe daemon .SH SYNOPSIS .B spiped {\-e | \-d} \-s \-t \-k .br [\-DfFj] [\-n ] [\-o ] [\-p ] [{\-r | \-R}] .SH OPTIONS .TP .B \-e Take unencrypted connections from the source socket and send encrypted connections to the target socket. .TP .B \-d Take encrypted connections from the source socket and send unencrypted connections to the target socket. .TP .B \-s Address on which spiped should listen for incoming connections. Must be in one of the following formats: /absolute/path/to/unix/socket host.name:port [ip.v4.ad.dr]:port [ipv6::addr]:port Note that hostnames are resolved when spiped is launched and are not re\-resolved later; thus if DNS entries change spiped will continue to connect to the expired address. .TP .B \-t Address to which spiped should connect. .TP .B \-k Use the provided key file to authenticate and encrypt. .TP .B \-D Wait for DNS. Normally when spiped is launched it resolves addresses and binds to its source socket before the parent process returns; with this option it will daemonize first and retry failed DNS lookups until they succeed. This allows spiped to launch even if DNS isn't set up yet, but at the expense of losing the guarantee that once spiped has finished launching it will be ready to create pipes. .TP .B \-f Use fast/weak handshaking: This reduces the CPU time spent in the initial connection setup, at the expense of losing perfect forward secrecy. .TP .B \-F Run in foreground. This can be useful with systems like daemontools. .TP .B \-j Disable transport layer keep-alives. (By default they are enabled.) .TP .B \-n Limit on the number of simultaneous connections allowed. Defaults to 100 connections. .TP .B \-o Timeout, in seconds, after which an attempt to connect to the target or a protocol handshake will be aborted (and the connection dropped) if not completed. Defaults to 5s. .TP .B \-p File to which spiped's process ID should be written. Defaults to .pid (in the current directory if is not an absolute path). .TP .B \-r Re-resolve the address of every seconds. Defaults to re-resolution every 60 seconds. .TP .B \-R Disable target address re-resolution. .SH SEE ALSO .BR spipe (1). spiped-1.3.1/spiped/dispatch.h000644 001751 001751 00000002057 12132205630 017666 0ustar00cpercivacperciva000000 000000 #ifndef _DISPATCH_H_ #define _DISPATCH_H_ #include /* Opaque structures. */ struct proto_secret; struct sock_addr; /** * dispatch_accept(s, tgt, rtime, sas, decr, nofps, nokeepalive, K, nconn_max, * timeo): * Start accepting connections on the socket ${s}. Connect to the target * ${tgt}, re-resolving it every ${rtime} seconds if ${rtime} > 0; on address * resolution failure use the most recent successfully obtained addresses, or * the addresses ${sas}. If ${decr} is 0, encrypt the outgoing connections; if * ${decr} is non-zero, decrypt the incoming connections. Don't accept more * than ${nconn_max} connections. If ${nofps} is non-zero, don't use perfect * forward secrecy. Enable transport layer keep-alives (if applicable) if and * only if ${nokeepalive} is zero. Drop connections if the handshake or * connecting to the target takes more than ${timeo} seconds. */ int dispatch_accept(int, const char *, double, struct sock_addr **, int, int, int, const struct proto_secret *, size_t, double); #endif /* !_DISPATCH_H_ */ spiped-1.3.1/spiped/main.c000644 001751 001751 00000011453 12132205630 017006 0ustar00cpercivacperciva000000 000000 #include #include #include #include #include #include "asprintf.h" #include "daemonize.h" #include "events.h" #include "sock.h" #include "warnp.h" #include "dispatch.h" #include "proto_crypt.h" static void usage(void) { fprintf(stderr, "usage: spiped {-e | -d} -s " "-t -k \n" " [-DfFj] [-n ] " "[-o ] [-p ]\n" " [{-r | -R}]\n"); exit(1); } /* Simplify error-handling in command-line parse loop. */ #define OPT_EPARSE(opt, arg) do { \ warnp("Error parsing argument: -%c %s", opt, arg); \ exit(1); \ } while (0) int main(int argc, char * argv[]) { /* Command-line parameters. */ int opt_d = 0; int opt_D = 0; int opt_e = 0; int opt_f = 0; int opt_F = 0; int opt_j = 0; const char * opt_k = NULL; intmax_t opt_n = 0; double opt_o = 0.0; char * opt_p = NULL; double opt_r = 0.0; int opt_R = 0; const char * opt_s = NULL; const char * opt_t = NULL; /* Working variables. */ struct sock_addr ** sas_s; struct sock_addr ** sas_t; struct proto_secret * K; int ch; int s; WARNP_INIT; /* Parse the command line. */ while ((ch = getopt(argc, argv, "dDefFjk:n:o:r:Rp:s:t:")) != -1) { switch (ch) { case 'd': if (opt_d || opt_e) usage(); opt_d = 1; break; case 'D': if (opt_D) usage(); opt_D = 1; break; case 'e': if (opt_d || opt_e) usage(); opt_e = 1; break; case 'f': if (opt_f) usage(); opt_f = 1; break; case 'F': if (opt_F) usage(); opt_F = 1; break; case 'j': if (opt_j) usage(); opt_j = 1; break; case 'k': if (opt_k) usage(); opt_k = optarg; break; case 'n': if (opt_n != 0) usage(); if ((opt_n = strtoimax(optarg, NULL, 0)) == 0) { warn0("Invalid option: -n %s", optarg); exit(1); } break; case 'o': if (opt_o != 0.0) usage(); if ((opt_o = strtod(optarg, NULL)) == 0.0) { warn0("Invalid option: -o %s", optarg); exit(1); } break; case 'p': if (opt_p) usage(); if ((opt_p = strdup(optarg)) == NULL) OPT_EPARSE(ch, optarg); break; case 'r': if (opt_r != 0.0) usage(); if ((opt_r = strtod(optarg, NULL)) == 0.0) { warn0("Invalid option: -r %s", optarg); exit(1); } break; case 'R': if (opt_R) usage(); opt_R = 1; break; case 's': if (opt_s) usage(); opt_s = optarg; break; case 't': if (opt_t) usage(); opt_t = optarg; break; default: usage(); } } /* We should have processed all the arguments. */ if (argc != optind) usage(); /* Set defaults. */ if (opt_n == 0) opt_n = 100; if (opt_o == 0.0) opt_o = 5.0; if (opt_r == 0.0) opt_r = 60.0; /* Sanity-check options. */ if (!opt_d && !opt_e) usage(); if (opt_k == NULL) usage(); if ((opt_n < 0) || (opt_n > 500)) usage(); if (!(opt_o > 0.0)) usage(); if ((opt_r != 60.0) && opt_R) usage(); if (opt_s == NULL) usage(); if (opt_t == NULL) usage(); /* Figure out where our pid should be written. */ if (opt_p == NULL) { if (asprintf(&opt_p, "%s.pid", opt_s) == -1) { warnp("asprintf"); exit(1); } } /* Daemonize early if we're going to wait for DNS to be ready. */ if (opt_D && !opt_F && daemonize(opt_p)) { warnp("Failed to daemonize"); exit(1); } /* Resolve source address. */ while ((sas_s = sock_resolve(opt_s)) == NULL) { if (!opt_D) { warnp("Error resolving socket address: %s", opt_s); exit(1); } sleep(1); } if (sas_s[0] == NULL) { warn0("No addresses found for %s", opt_s); exit(1); } /* Resolve target address. */ while ((sas_t = sock_resolve(opt_t)) == NULL) { if (!opt_D) { warnp("Error resolving socket address: %s", opt_t); exit(1); } sleep(1); } if (sas_t[0] == NULL) { warn0("No addresses found for %s", opt_t); exit(1); } /* Load the keying data. */ if ((K = proto_crypt_secret(opt_k)) == NULL) { warnp("Error reading shared secret"); exit(1); } /* Create and bind a socket, and mark it as listening. */ if (sas_s[1] != NULL) warn0("Listening on first of multiple addresses found for %s", opt_s); if ((s = sock_listener(sas_s[0])) == -1) exit(1); /* Daemonize and write pid. */ if (!opt_F && daemonize(opt_p)) { warnp("Failed to daemonize"); exit(1); } /* Start accepting connections. */ if (dispatch_accept(s, opt_t, opt_R ? 0.0 : opt_r, sas_t, opt_d, opt_f, opt_j, K, opt_n, opt_o)) { warnp("Failed to initialize connection acceptor"); exit(1); } /* Infinite loop handling events. */ do { if (events_run()) { warnp("Error running event loop"); exit(1); } } while (1); /* NOTREACHED */ /* * If we could reach this point, we would free memory, close sockets, * and otherwise clean up here. */ } spiped-1.3.1/spiped/Makefile000644 001751 001751 00000012627 12132206317 017365 0ustar00cpercivacperciva000000 000000 .POSIX: PROG=spiped MAN1=spiped.1 SRCS=main.c dispatch.c proto_conn.c proto_crypt.c proto_handshake.c proto_pipe.c sha256.c elasticarray.c ptrheap.c timerqueue.c dnsthread.c asprintf.c daemonize.c entropy.c monoclock.c noeintr.c sock.c sock_util.c warnp.c events_immediate.c events_network.c events_timer.c events.c network_accept.c network_buf.c network_connect.c crypto_aesctr.c crypto_dh.c crypto_dh_group14.c crypto_entropy.c crypto_verify_bytes.c IDIRS=-I ../proto -I ../lib/alg -I ../lib/datastruct -I ../lib/dnsthread -I ../lib/util -I ../lib/events -I ../lib/network -I ../lib/crypto LDADD_REQ=-lcrypto -lpthread all: ${PROG} install:${PROG} mkdir -p ${BINDIR} cp ${PROG} ${BINDIR}/_inst.${PROG}.$$$$_ && \ strip ${BINDIR}/_inst.${PROG}.$$$$_ && \ chmod 0555 ${BINDIR}/_inst.${PROG}.$$$$_ && \ mv -f ${BINDIR}/_inst.${PROG}.$$$$_ ${BINDIR}/${PROG} if ! [ -z "${MAN1DIR}" ]; then \ for MPAGE in ${MAN1}; do \ cp $$MPAGE ${MAN1DIR}/_inst.$$MPAGE.$$$$_ && \ chmod 0444 ${MAN1DIR}/_inst.$$MPAGE.$$$$_ && \ mv -f ${MAN1DIR}/_inst.$$MPAGE.$$$$_ ${MAN1DIR}/$$MPAGE; \ done; \ fi clean: rm -f ${PROG} ${SRCS:.c=.o} ${PROG}:${SRCS:.c=.o} ${CC} -o ${PROG} ${SRCS:.c=.o} ${LDADD_EXTRA} ${LDADD_REQ} ${LDADD_POSIX} main.o: main.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c main.c -o main.o dispatch.o: dispatch.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c dispatch.c -o dispatch.o proto_conn.o: ../proto/proto_conn.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../proto/proto_conn.c -o proto_conn.o proto_crypt.o: ../proto/proto_crypt.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../proto/proto_crypt.c -o proto_crypt.o proto_handshake.o: ../proto/proto_handshake.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../proto/proto_handshake.c -o proto_handshake.o proto_pipe.o: ../proto/proto_pipe.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../proto/proto_pipe.c -o proto_pipe.o sha256.o: ../lib/alg/sha256.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/alg/sha256.c -o sha256.o elasticarray.o: ../lib/datastruct/elasticarray.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/datastruct/elasticarray.c -o elasticarray.o ptrheap.o: ../lib/datastruct/ptrheap.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/datastruct/ptrheap.c -o ptrheap.o timerqueue.o: ../lib/datastruct/timerqueue.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/datastruct/timerqueue.c -o timerqueue.o dnsthread.o: ../lib/dnsthread/dnsthread.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/dnsthread/dnsthread.c -o dnsthread.o asprintf.o: ../lib/util/asprintf.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/asprintf.c -o asprintf.o daemonize.o: ../lib/util/daemonize.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/daemonize.c -o daemonize.o entropy.o: ../lib/util/entropy.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/entropy.c -o entropy.o monoclock.o: ../lib/util/monoclock.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/monoclock.c -o monoclock.o noeintr.o: ../lib/util/noeintr.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/noeintr.c -o noeintr.o sock.o: ../lib/util/sock.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/sock.c -o sock.o sock_util.o: ../lib/util/sock_util.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/sock_util.c -o sock_util.o warnp.o: ../lib/util/warnp.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/util/warnp.c -o warnp.o events_immediate.o: ../lib/events/events_immediate.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/events/events_immediate.c -o events_immediate.o events_network.o: ../lib/events/events_network.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/events/events_network.c -o events_network.o events_timer.o: ../lib/events/events_timer.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/events/events_timer.c -o events_timer.o events.o: ../lib/events/events.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/events/events.c -o events.o network_accept.o: ../lib/network/network_accept.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/network/network_accept.c -o network_accept.o network_buf.o: ../lib/network/network_buf.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/network/network_buf.c -o network_buf.o network_connect.o: ../lib/network/network_connect.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/network/network_connect.c -o network_connect.o crypto_aesctr.o: ../lib/crypto/crypto_aesctr.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/crypto/crypto_aesctr.c -o crypto_aesctr.o crypto_dh.o: ../lib/crypto/crypto_dh.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/crypto/crypto_dh.c -o crypto_dh.o crypto_dh_group14.o: ../lib/crypto/crypto_dh_group14.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/crypto/crypto_dh_group14.c -o crypto_dh_group14.o crypto_entropy.o: ../lib/crypto/crypto_entropy.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/crypto/crypto_entropy.c -o crypto_entropy.o crypto_verify_bytes.o: ../lib/crypto/crypto_verify_bytes.c ${CC} ${CFLAGS} -D_POSIX_C_SOURCE=200809L ${IDIRS} -c ../lib/crypto/crypto_verify_bytes.c -o crypto_verify_bytes.o