spiped 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ext/spiped/extconf.rb +3 -0
- data/ext/spiped/spiped-source/BUILDING +46 -0
- data/ext/spiped/spiped-source/CHANGELOG +44 -0
- data/ext/spiped/spiped-source/COPYRIGHT +33 -0
- data/ext/spiped/spiped-source/Makefile +47 -0
- data/ext/spiped/spiped-source/Makefile.POSIX +27 -0
- data/ext/spiped/spiped-source/Makefile.inc +20 -0
- data/ext/spiped/spiped-source/Makefile.prog +23 -0
- data/ext/spiped/spiped-source/POSIX/README +10 -0
- data/ext/spiped/spiped-source/POSIX/posix-cflags.sh +10 -0
- data/ext/spiped/spiped-source/POSIX/posix-clock_realtime.c +3 -0
- data/ext/spiped/spiped-source/POSIX/posix-l.c +1 -0
- data/ext/spiped/spiped-source/POSIX/posix-l.sh +14 -0
- data/ext/spiped/spiped-source/POSIX/posix-msg_nosignal.c +3 -0
- data/ext/spiped/spiped-source/README +198 -0
- data/ext/spiped/spiped-source/STYLE +151 -0
- data/ext/spiped/spiped-source/lib/dnsthread/dnsthread.c +464 -0
- data/ext/spiped/spiped-source/lib/dnsthread/dnsthread.h +45 -0
- data/ext/spiped/spiped-source/libcperciva/alg/sha256.c +442 -0
- data/ext/spiped/spiped-source/libcperciva/alg/sha256.h +95 -0
- data/ext/spiped/spiped-source/libcperciva/cpusupport/Build/cpusupport-X86-AESNI.c +13 -0
- data/ext/spiped/spiped-source/libcperciva/cpusupport/Build/cpusupport-X86-CPUID.c +8 -0
- data/ext/spiped/spiped-source/libcperciva/cpusupport/Build/cpusupport.sh +37 -0
- data/ext/spiped/spiped-source/libcperciva/cpusupport/cpusupport.h +63 -0
- data/ext/spiped/spiped-source/libcperciva/cpusupport/cpusupport_x86_aesni.c +30 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes.c +166 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes.h +31 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes_aesni.c +229 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes_aesni.h +31 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aesctr.c +124 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aesctr.h +41 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh.c +293 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh.h +43 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh_group14.c +46 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh_group14.h +9 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_entropy.c +215 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_entropy.h +14 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_verify_bytes.c +21 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_verify_bytes.h +14 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/elasticarray.c +276 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/elasticarray.h +167 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/mpool.h +85 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/ptrheap.c +334 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/ptrheap.h +89 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/timerqueue.c +241 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/timerqueue.h +60 -0
- data/ext/spiped/spiped-source/libcperciva/events/events.c +203 -0
- data/ext/spiped/spiped-source/libcperciva/events/events.h +106 -0
- data/ext/spiped/spiped-source/libcperciva/events/events_immediate.c +149 -0
- data/ext/spiped/spiped-source/libcperciva/events/events_internal.h +95 -0
- data/ext/spiped/spiped-source/libcperciva/events/events_network.c +347 -0
- data/ext/spiped/spiped-source/libcperciva/events/events_network_selectstats.c +106 -0
- data/ext/spiped/spiped-source/libcperciva/events/events_timer.c +273 -0
- data/ext/spiped/spiped-source/libcperciva/network/network.h +95 -0
- data/ext/spiped/spiped-source/libcperciva/network/network_accept.c +103 -0
- data/ext/spiped/spiped-source/libcperciva/network/network_connect.c +258 -0
- data/ext/spiped/spiped-source/libcperciva/network/network_read.c +155 -0
- data/ext/spiped/spiped-source/libcperciva/network/network_write.c +188 -0
- data/ext/spiped/spiped-source/libcperciva/util/asprintf.c +49 -0
- data/ext/spiped/spiped-source/libcperciva/util/asprintf.h +16 -0
- data/ext/spiped/spiped-source/libcperciva/util/daemonize.c +134 -0
- data/ext/spiped/spiped-source/libcperciva/util/daemonize.h +10 -0
- data/ext/spiped/spiped-source/libcperciva/util/entropy.c +76 -0
- data/ext/spiped/spiped-source/libcperciva/util/entropy.h +13 -0
- data/ext/spiped/spiped-source/libcperciva/util/imalloc.h +33 -0
- data/ext/spiped/spiped-source/libcperciva/util/insecure_memzero.c +19 -0
- data/ext/spiped/spiped-source/libcperciva/util/insecure_memzero.h +33 -0
- data/ext/spiped/spiped-source/libcperciva/util/monoclock.c +52 -0
- data/ext/spiped/spiped-source/libcperciva/util/monoclock.h +14 -0
- data/ext/spiped/spiped-source/libcperciva/util/noeintr.c +54 -0
- data/ext/spiped/spiped-source/libcperciva/util/noeintr.h +14 -0
- data/ext/spiped/spiped-source/libcperciva/util/sock.c +472 -0
- data/ext/spiped/spiped-source/libcperciva/util/sock.h +56 -0
- data/ext/spiped/spiped-source/libcperciva/util/sock_internal.h +14 -0
- data/ext/spiped/spiped-source/libcperciva/util/sock_util.c +271 -0
- data/ext/spiped/spiped-source/libcperciva/util/sock_util.h +51 -0
- data/ext/spiped/spiped-source/libcperciva/util/sysendian.h +146 -0
- data/ext/spiped/spiped-source/libcperciva/util/warnp.c +76 -0
- data/ext/spiped/spiped-source/libcperciva/util/warnp.h +59 -0
- data/ext/spiped/spiped-source/proto/proto_conn.c +362 -0
- data/ext/spiped/spiped-source/proto/proto_conn.h +25 -0
- data/ext/spiped/spiped-source/proto/proto_crypt.c +396 -0
- data/ext/spiped/spiped-source/proto/proto_crypt.h +102 -0
- data/ext/spiped/spiped-source/proto/proto_handshake.c +330 -0
- data/ext/spiped/spiped-source/proto/proto_handshake.h +30 -0
- data/ext/spiped/spiped-source/proto/proto_pipe.c +202 -0
- data/ext/spiped/spiped-source/proto/proto_pipe.h +23 -0
- data/ext/spiped/spiped-source/spipe/Makefile +90 -0
- data/ext/spiped/spiped-source/spipe/README +24 -0
- data/ext/spiped/spiped-source/spipe/main.c +178 -0
- data/ext/spiped/spiped-source/spipe/pushbits.c +101 -0
- data/ext/spiped/spiped-source/spipe/pushbits.h +10 -0
- data/ext/spiped/spiped-source/spipe/spipe.1 +60 -0
- data/ext/spiped/spiped-source/spiped/Makefile +98 -0
- data/ext/spiped/spiped-source/spiped/README +62 -0
- data/ext/spiped/spiped-source/spiped/dispatch.c +214 -0
- data/ext/spiped/spiped-source/spiped/dispatch.h +27 -0
- data/ext/spiped/spiped-source/spiped/main.c +267 -0
- data/ext/spiped/spiped-source/spiped/spiped.1 +112 -0
- data/lib/spiped.rb +3 -0
- metadata +143 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
#ifndef _ENTROPY_H_
|
2
|
+
#define _ENTROPY_H_
|
3
|
+
|
4
|
+
#include <stddef.h>
|
5
|
+
#include <stdint.h>
|
6
|
+
|
7
|
+
/**
|
8
|
+
* entropy_read(buf, buflen):
|
9
|
+
* Fill the given buffer with random bytes provided by the operating system.
|
10
|
+
*/
|
11
|
+
int entropy_read(uint8_t *, size_t);
|
12
|
+
|
13
|
+
#endif /* !_ENTROPY_H_ */
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#ifndef _IMALLOC_H_
|
2
|
+
#define _IMALLOC_H_
|
3
|
+
|
4
|
+
#include <errno.h>
|
5
|
+
#include <stdint.h>
|
6
|
+
#include <stdlib.h>
|
7
|
+
|
8
|
+
/**
|
9
|
+
* imalloc(nrec, reclen):
|
10
|
+
* Allocate ${nrec} records of length ${reclen}. Check for size_t overflow.
|
11
|
+
*/
|
12
|
+
static inline void *
|
13
|
+
imalloc(size_t nrec, size_t reclen)
|
14
|
+
{
|
15
|
+
|
16
|
+
if (nrec > SIZE_MAX / reclen) {
|
17
|
+
errno = ENOMEM;
|
18
|
+
return (NULL);
|
19
|
+
} else {
|
20
|
+
return (malloc(nrec * reclen));
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
/**
|
25
|
+
* IMALLOC(p, nrec, type):
|
26
|
+
* Allocate ${nrec} records of type ${type} and store the pointer in ${p}.
|
27
|
+
* Return non-zero on failure.
|
28
|
+
*/
|
29
|
+
#define IMALLOC(p, nrec, type) \
|
30
|
+
((((p) = (type *)imalloc((nrec), sizeof(type))) == NULL) && \
|
31
|
+
((nrec) > 0))
|
32
|
+
|
33
|
+
#endif /* !_IMALLOC_H_ */
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#include <stddef.h>
|
2
|
+
#include <stdint.h>
|
3
|
+
|
4
|
+
#include "insecure_memzero.h"
|
5
|
+
|
6
|
+
/* Fucntion which does the zeroing. */
|
7
|
+
static void
|
8
|
+
insecure_memzero_func(volatile void * buf, size_t len)
|
9
|
+
{
|
10
|
+
volatile uint8_t * _buf = buf;
|
11
|
+
size_t i;
|
12
|
+
|
13
|
+
for (i = 0; i < len; i++)
|
14
|
+
_buf[i] = 0;
|
15
|
+
}
|
16
|
+
|
17
|
+
/* Pointer to memory-zeroing function. */
|
18
|
+
void (* volatile insecure_memzero_ptr)(volatile void *, size_t) =
|
19
|
+
insecure_memzero_func;
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#ifndef _INSECURE_MEMZERO_H_
|
2
|
+
#define _INSECURE_MEMZERO_H_
|
3
|
+
|
4
|
+
#include <stddef.h>
|
5
|
+
|
6
|
+
/* Pointer to memory-zeroing function. */
|
7
|
+
extern void (* volatile insecure_memzero_ptr)(volatile void *, size_t);
|
8
|
+
|
9
|
+
/**
|
10
|
+
* insecure_memzero(buf, len):
|
11
|
+
* Attempt to zero ${len} bytes at ${buf} in spite of optimizing compilers'
|
12
|
+
* best (standards-compliant) attempts to remove the buffer-zeroing. In
|
13
|
+
* particular, to avoid performing the zeroing, a compiler would need to
|
14
|
+
* use optimistic devirtualization; recognize that non-volatile objects do not
|
15
|
+
* need to be treated as volatile, even if they are accessed via volatile
|
16
|
+
* qualified pointers; and perform link-time optimization; in addition to the
|
17
|
+
* dead-code elimination which often causes buffer-zeroing to be elided.
|
18
|
+
*
|
19
|
+
* Note however that zeroing a buffer does nto guarantee that the data held
|
20
|
+
* in the buffer is not stored elsewhere; in particular, there may be copies
|
21
|
+
* held in CPU registers or in anonymous allocations on the stack, even if
|
22
|
+
* every named variable is successfully sanitized. Solving the "wipe data
|
23
|
+
* from the system" problem will require a C language extension which does not
|
24
|
+
* yet exist.
|
25
|
+
*/
|
26
|
+
static inline void
|
27
|
+
insecure_memzero(volatile void * buf, size_t len)
|
28
|
+
{
|
29
|
+
|
30
|
+
(insecure_memzero_ptr)(buf, len);
|
31
|
+
}
|
32
|
+
|
33
|
+
#endif /* !_INSECURE_MEMZERO_H_ */
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#include <sys/time.h>
|
2
|
+
|
3
|
+
#include <time.h>
|
4
|
+
|
5
|
+
#include "warnp.h"
|
6
|
+
|
7
|
+
#include "monoclock.h"
|
8
|
+
|
9
|
+
/**
|
10
|
+
* monoclock_get(tv):
|
11
|
+
* Store the current time in ${tv}. If CLOCK_MONOTONIC is available, use
|
12
|
+
* that clock; if CLOCK_MONOTONIC is unavailable, use CLOCK_REALTIME (if
|
13
|
+
* available) or gettimeofday(2).
|
14
|
+
*/
|
15
|
+
int
|
16
|
+
monoclock_get(struct timeval * tv)
|
17
|
+
{
|
18
|
+
#if defined(CLOCK_MONOTONIC) || !defined(POSIXFAIL_CLOCK_REALTIME)
|
19
|
+
struct timespec tp;
|
20
|
+
#endif
|
21
|
+
|
22
|
+
#ifdef CLOCK_MONOTONIC
|
23
|
+
if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
|
24
|
+
tv->tv_sec = tp.tv_sec;
|
25
|
+
tv->tv_usec = tp.tv_nsec / 1000;
|
26
|
+
} else if ((errno != ENOSYS) && (errno != EINVAL)) {
|
27
|
+
warnp("clock_gettime(CLOCK_MONOTONIC)");
|
28
|
+
goto err0;
|
29
|
+
} else
|
30
|
+
#endif
|
31
|
+
#ifndef POSIXFAIL_CLOCK_REALTIME
|
32
|
+
if (clock_gettime(CLOCK_REALTIME, &tp) == 0) {
|
33
|
+
tv->tv_sec = tp.tv_sec;
|
34
|
+
tv->tv_usec = tp.tv_nsec / 1000;
|
35
|
+
} else {
|
36
|
+
warnp("clock_gettime(CLOCK_REALTIME)");
|
37
|
+
goto err0;
|
38
|
+
}
|
39
|
+
#else
|
40
|
+
if (gettimeofday(tv, NULL)) {
|
41
|
+
warnp("gettimeofday");
|
42
|
+
goto err0;
|
43
|
+
}
|
44
|
+
#endif
|
45
|
+
|
46
|
+
/* Success! */
|
47
|
+
return (0);
|
48
|
+
|
49
|
+
err0:
|
50
|
+
/* Failure! */
|
51
|
+
return (-1);
|
52
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#ifndef _MONOCLOCK_H_
|
2
|
+
#define _MONOCLOCK_H_
|
3
|
+
|
4
|
+
#include <sys/time.h>
|
5
|
+
|
6
|
+
/**
|
7
|
+
* monoclock_get(tv):
|
8
|
+
* Store the current time in ${tv}. If CLOCK_MONOTONIC is available, use
|
9
|
+
* that clock; if CLOCK_MONOTONIC is unavailable, use CLOCK_REALTIME (if
|
10
|
+
* available) or gettimeofday(2).
|
11
|
+
*/
|
12
|
+
int monoclock_get(struct timeval *);
|
13
|
+
|
14
|
+
#endif /* !_MONOCLOCK_H_ */
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#include <assert.h>
|
2
|
+
#include <errno.h>
|
3
|
+
#include <limits.h>
|
4
|
+
#include <stdint.h>
|
5
|
+
#include <unistd.h>
|
6
|
+
|
7
|
+
#include "noeintr.h"
|
8
|
+
|
9
|
+
/**
|
10
|
+
* noeintr_write(d, buf, nbytes):
|
11
|
+
* Write ${nbytes} bytes of data from ${buf} to the file descriptor ${d} per
|
12
|
+
* the write(2) system call, but looping until completion if interrupted by
|
13
|
+
* a signal. Return ${nbytes} on success or -1 on error.
|
14
|
+
*/
|
15
|
+
ssize_t
|
16
|
+
noeintr_write(int d, const void * buf, size_t nbyte)
|
17
|
+
{
|
18
|
+
const uint8_t * p = buf;
|
19
|
+
size_t len = nbyte;
|
20
|
+
ssize_t lenwrit;
|
21
|
+
|
22
|
+
/* Implementation-defined: Don't allow oversized writes. */
|
23
|
+
assert(nbyte <= SSIZE_MAX);
|
24
|
+
|
25
|
+
/* Loop until we have no data left to write. */
|
26
|
+
while (len > 0) {
|
27
|
+
if ((lenwrit = write(d, p, len)) == -1) {
|
28
|
+
/* EINTR is harmless. */
|
29
|
+
if (errno == EINTR)
|
30
|
+
continue;
|
31
|
+
|
32
|
+
/* Anything else isn't. */
|
33
|
+
goto err0;
|
34
|
+
}
|
35
|
+
|
36
|
+
/* Sanity check. */
|
37
|
+
assert(lenwrit >= 0);
|
38
|
+
assert(lenwrit <= (ssize_t)len);
|
39
|
+
|
40
|
+
/*
|
41
|
+
* We might have done a partial write; advance the buffer
|
42
|
+
* pointer and adjust the remaining write length.
|
43
|
+
*/
|
44
|
+
p += lenwrit;
|
45
|
+
len -= lenwrit;
|
46
|
+
}
|
47
|
+
|
48
|
+
/* Success! */
|
49
|
+
return (nbyte);
|
50
|
+
|
51
|
+
err0:
|
52
|
+
/* Failure! */
|
53
|
+
return (-1);
|
54
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#ifndef _NOEINTR_H_
|
2
|
+
#define _NOEINTR_H_
|
3
|
+
|
4
|
+
#include <unistd.h>
|
5
|
+
|
6
|
+
/**
|
7
|
+
* noeintr_write(d, buf, nbytes):
|
8
|
+
* Write ${nbytes} bytes of data from ${buf} to the file descriptor ${d} per
|
9
|
+
* the write(2) system call, but looping until completion if interrupted by
|
10
|
+
* a signal. Return ${nbytes} on success or -1 on error.
|
11
|
+
*/
|
12
|
+
ssize_t noeintr_write(int, const void *, size_t);
|
13
|
+
|
14
|
+
#endif /* _NOEINTR_H_ */
|
@@ -0,0 +1,472 @@
|
|
1
|
+
#include <sys/types.h>
|
2
|
+
#include <sys/socket.h>
|
3
|
+
#include <sys/un.h>
|
4
|
+
|
5
|
+
#include <netinet/in.h>
|
6
|
+
|
7
|
+
#include <arpa/inet.h>
|
8
|
+
|
9
|
+
#include <errno.h>
|
10
|
+
#include <fcntl.h>
|
11
|
+
#include <netdb.h>
|
12
|
+
#include <stdint.h>
|
13
|
+
#include <string.h>
|
14
|
+
#include <unistd.h>
|
15
|
+
|
16
|
+
#include "imalloc.h"
|
17
|
+
#include "warnp.h"
|
18
|
+
|
19
|
+
#include "sock.h"
|
20
|
+
#include "sock_internal.h"
|
21
|
+
|
22
|
+
/* Convert a path into a socket address. */
|
23
|
+
static struct sock_addr **
|
24
|
+
sock_resolve_unix(const char * addr)
|
25
|
+
{
|
26
|
+
struct sock_addr ** sas;
|
27
|
+
struct sock_addr * sa;
|
28
|
+
struct sockaddr_un * sa_un;
|
29
|
+
|
30
|
+
/* Allocate and populate a sockaddr_un structure. */
|
31
|
+
if ((sa_un = calloc(1, sizeof(struct sockaddr_un))) == NULL)
|
32
|
+
goto err0;
|
33
|
+
sa_un->sun_family = AF_UNIX;
|
34
|
+
if (strlen(addr) >= sizeof(sa_un->sun_path)) {
|
35
|
+
warn0("socket path too long: %s", addr);
|
36
|
+
goto err1;
|
37
|
+
}
|
38
|
+
strcpy(sa_un->sun_path, addr);
|
39
|
+
|
40
|
+
/* Allocate and populate our wrapper. */
|
41
|
+
if ((sa = malloc(sizeof(struct sock_addr))) == NULL)
|
42
|
+
goto err1;
|
43
|
+
sa->ai_family = AF_UNIX;
|
44
|
+
sa->ai_socktype = SOCK_STREAM;
|
45
|
+
sa->name = (struct sockaddr *)sa_un;
|
46
|
+
sa->namelen = sizeof(struct sockaddr_un);
|
47
|
+
|
48
|
+
/* Allocate and populate an array of pointers. */
|
49
|
+
if ((sas = malloc(2 * sizeof(struct sock_addr *))) == NULL)
|
50
|
+
goto err2;
|
51
|
+
sas[0] = sa;
|
52
|
+
sas[1] = NULL;
|
53
|
+
|
54
|
+
/* Success! */
|
55
|
+
return (sas);
|
56
|
+
|
57
|
+
err2:
|
58
|
+
free(sa);
|
59
|
+
err1:
|
60
|
+
free(sa_un);
|
61
|
+
err0:
|
62
|
+
/* Failure! */
|
63
|
+
return (NULL);
|
64
|
+
}
|
65
|
+
|
66
|
+
/* Resolve a host into a list of socket addresses. */
|
67
|
+
static struct sock_addr **
|
68
|
+
sock_resolve_host(const char * addr, const char * ports)
|
69
|
+
{
|
70
|
+
struct addrinfo hints;
|
71
|
+
struct addrinfo * res;
|
72
|
+
struct addrinfo * r;
|
73
|
+
struct sock_addr ** sas;
|
74
|
+
size_t n;
|
75
|
+
int error;
|
76
|
+
|
77
|
+
/* Create hints structure. */
|
78
|
+
memset(&hints, 0, sizeof(hints));
|
79
|
+
hints.ai_family = AF_UNSPEC;
|
80
|
+
hints.ai_socktype = SOCK_STREAM;
|
81
|
+
hints.ai_protocol = IPPROTO_TCP;
|
82
|
+
|
83
|
+
/* Perform DNS lookup. */
|
84
|
+
if ((error = getaddrinfo(addr, ports, &hints, &res)) != 0) {
|
85
|
+
warn0("Error looking up %s: %s", addr, gai_strerror(error));
|
86
|
+
goto err0;
|
87
|
+
}
|
88
|
+
|
89
|
+
/* Count addresses returned. */
|
90
|
+
for (n = 0, r = res; r != NULL; r = r->ai_next)
|
91
|
+
n++;
|
92
|
+
|
93
|
+
/* Allocate our response array. */
|
94
|
+
if (IMALLOC(sas, n + 1, struct sock_addr *))
|
95
|
+
goto err1;
|
96
|
+
|
97
|
+
/* Create address structures. */
|
98
|
+
for (n = 0, r = res; r != NULL; n++, r = r->ai_next) {
|
99
|
+
/* Allocate a structure. */
|
100
|
+
if ((sas[n] = malloc(sizeof(struct sock_addr))) == NULL)
|
101
|
+
goto err2;
|
102
|
+
|
103
|
+
/* Copy in the address metadata. */
|
104
|
+
sas[n]->ai_family = r->ai_family;
|
105
|
+
sas[n]->ai_socktype = r->ai_socktype;
|
106
|
+
sas[n]->namelen = r->ai_addrlen;
|
107
|
+
|
108
|
+
/* Duplicate the address. */
|
109
|
+
if ((sas[n]->name = malloc(sas[n]->namelen)) == NULL)
|
110
|
+
goto err3;
|
111
|
+
memcpy(sas[n]->name, r->ai_addr, sas[n]->namelen);
|
112
|
+
}
|
113
|
+
|
114
|
+
/* Terminate array with a NULL. */
|
115
|
+
sas[n] = NULL;
|
116
|
+
|
117
|
+
/* Free the linked list of addresses returned by getaddrinfo. */
|
118
|
+
freeaddrinfo(res);
|
119
|
+
|
120
|
+
/* Success! */
|
121
|
+
return (sas);
|
122
|
+
|
123
|
+
err3:
|
124
|
+
free(sas[n]);
|
125
|
+
err2:
|
126
|
+
for (; n > 0; n--)
|
127
|
+
sock_addr_free(sas[n - 1]);
|
128
|
+
free(sas);
|
129
|
+
err1:
|
130
|
+
freeaddrinfo(res);
|
131
|
+
err0:
|
132
|
+
/* Failure! */
|
133
|
+
return (NULL);
|
134
|
+
}
|
135
|
+
|
136
|
+
/* Parse an IPv6 address into a socket address. */
|
137
|
+
static struct sock_addr **
|
138
|
+
sock_resolve_ipv6(const char * addr, in_port_t p)
|
139
|
+
{
|
140
|
+
struct sock_addr ** sas;
|
141
|
+
struct sock_addr * sa;
|
142
|
+
struct sockaddr_in6 * sin6;
|
143
|
+
|
144
|
+
/* Allocate and populate a sockaddr_in6 structure. */
|
145
|
+
if ((sin6 = calloc(1, sizeof(struct sockaddr_in6))) == NULL)
|
146
|
+
goto err0;
|
147
|
+
sin6->sin6_family = AF_INET6;
|
148
|
+
sin6->sin6_port = htons(p);
|
149
|
+
if (inet_pton(AF_INET6, addr, &sin6->sin6_addr) != 1) {
|
150
|
+
warn0("Error parsing IP address: %s", addr);
|
151
|
+
goto err1;
|
152
|
+
}
|
153
|
+
|
154
|
+
/* Allocate and populate our wrapper. */
|
155
|
+
if ((sa = malloc(sizeof(struct sock_addr))) == NULL)
|
156
|
+
goto err1;
|
157
|
+
sa->ai_family = AF_INET6;
|
158
|
+
sa->ai_socktype = SOCK_STREAM;
|
159
|
+
sa->name = (struct sockaddr *)sin6;
|
160
|
+
sa->namelen = sizeof(struct sockaddr_in6);
|
161
|
+
|
162
|
+
/* Allocate and populate an array of pointers. */
|
163
|
+
if ((sas = malloc(2 * sizeof(struct sock_addr *))) == NULL)
|
164
|
+
goto err2;
|
165
|
+
sas[0] = sa;
|
166
|
+
sas[1] = NULL;
|
167
|
+
|
168
|
+
/* Success! */
|
169
|
+
return (sas);
|
170
|
+
|
171
|
+
err2:
|
172
|
+
free(sa);
|
173
|
+
err1:
|
174
|
+
free(sin6);
|
175
|
+
err0:
|
176
|
+
/* Failure! */
|
177
|
+
return (NULL);
|
178
|
+
}
|
179
|
+
|
180
|
+
/* Parse an IPv4 address into a socket address. */
|
181
|
+
static struct sock_addr **
|
182
|
+
sock_resolve_ipv4(const char * addr, in_port_t p)
|
183
|
+
{
|
184
|
+
struct sock_addr ** sas;
|
185
|
+
struct sock_addr * sa;
|
186
|
+
struct sockaddr_in * sin;
|
187
|
+
|
188
|
+
/* Allocate and populate a sockaddr_in structure. */
|
189
|
+
if ((sin = calloc(1, sizeof(struct sockaddr_in))) == NULL)
|
190
|
+
goto err0;
|
191
|
+
sin->sin_family = AF_INET;
|
192
|
+
sin->sin_port = htons(p);
|
193
|
+
if (inet_pton(AF_INET, addr, &sin->sin_addr) != 1) {
|
194
|
+
warn0("Error parsing IP address: %s", addr);
|
195
|
+
goto err1;
|
196
|
+
}
|
197
|
+
|
198
|
+
/* Allocate and populate our wrapper. */
|
199
|
+
if ((sa = malloc(sizeof(struct sock_addr))) == NULL)
|
200
|
+
goto err1;
|
201
|
+
sa->ai_family = AF_INET;
|
202
|
+
sa->ai_socktype = SOCK_STREAM;
|
203
|
+
sa->name = (struct sockaddr *)sin;
|
204
|
+
sa->namelen = sizeof(struct sockaddr_in);
|
205
|
+
|
206
|
+
/* Allocate and populate an array of pointers. */
|
207
|
+
if ((sas = malloc(2 * sizeof(struct sock_addr *))) == NULL)
|
208
|
+
goto err2;
|
209
|
+
sas[0] = sa;
|
210
|
+
sas[1] = NULL;
|
211
|
+
|
212
|
+
/* Success! */
|
213
|
+
return (sas);
|
214
|
+
|
215
|
+
err2:
|
216
|
+
free(sa);
|
217
|
+
err1:
|
218
|
+
free(sin);
|
219
|
+
err0:
|
220
|
+
/* Failure! */
|
221
|
+
return (NULL);
|
222
|
+
}
|
223
|
+
|
224
|
+
/**
|
225
|
+
* sock_resolve(addr):
|
226
|
+
* Return a NULL-terminated array of pointers to sock_addr structures.
|
227
|
+
*/
|
228
|
+
struct sock_addr **
|
229
|
+
sock_resolve(const char * addr)
|
230
|
+
{
|
231
|
+
struct sock_addr ** res;
|
232
|
+
char * s;
|
233
|
+
char * ports;
|
234
|
+
char * ips;
|
235
|
+
long p;
|
236
|
+
|
237
|
+
/* If the address starts with '/', it's a unix socket. */
|
238
|
+
if (addr[0] == '/') {
|
239
|
+
res = sock_resolve_unix(addr);
|
240
|
+
goto done0;
|
241
|
+
}
|
242
|
+
|
243
|
+
/* Copy the address so that we can mangle it. */
|
244
|
+
if ((s = strdup(addr)) == NULL)
|
245
|
+
goto err0;
|
246
|
+
|
247
|
+
/* The address should end with :port. Look for the last ':'. */
|
248
|
+
if ((ports = strrchr(s, ':')) == NULL) {
|
249
|
+
warn0("Address must contain port number: %s", s);
|
250
|
+
goto err1;
|
251
|
+
}
|
252
|
+
*ports++ = '\0';
|
253
|
+
|
254
|
+
/* If the address doesn't start with '[', it's a host name. */
|
255
|
+
if (s[0] != '[') {
|
256
|
+
res = sock_resolve_host(s, ports);
|
257
|
+
goto done1;
|
258
|
+
}
|
259
|
+
|
260
|
+
/* The address (sans :port) should end with ']'. */
|
261
|
+
if (s[strlen(s) - 1] != ']') {
|
262
|
+
warn0("Invalid [IP address]: %s", s);
|
263
|
+
goto err1;
|
264
|
+
}
|
265
|
+
|
266
|
+
/* Extract the IP address string. */
|
267
|
+
ips = &s[1];
|
268
|
+
ips[strlen(ips) - 1] = '\0';
|
269
|
+
|
270
|
+
/*
|
271
|
+
* Parse the port number. If strtol fails to parse the port number,
|
272
|
+
* it will return 0; but that's fine since port 0 is invalid anyway.
|
273
|
+
*/
|
274
|
+
p = strtol(ports, NULL, 10);
|
275
|
+
if ((p <= 0) || (p >= 65536)) {
|
276
|
+
warn0("Invalid port number: %s", ports);
|
277
|
+
goto err1;
|
278
|
+
}
|
279
|
+
|
280
|
+
/* If the IP address contains ':', it's IPv6; otherwise, IPv4. */
|
281
|
+
if (strchr(ips, ':') != NULL)
|
282
|
+
res = sock_resolve_ipv6(ips, p);
|
283
|
+
else
|
284
|
+
res = sock_resolve_ipv4(ips, p);
|
285
|
+
|
286
|
+
done1:
|
287
|
+
/* Free string allocated by strdup. */
|
288
|
+
free(s);
|
289
|
+
done0:
|
290
|
+
/* Return result from sock_resolve_foo. */
|
291
|
+
return (res);
|
292
|
+
|
293
|
+
err1:
|
294
|
+
free(s);
|
295
|
+
err0:
|
296
|
+
/* Failure! */
|
297
|
+
return (NULL);
|
298
|
+
}
|
299
|
+
|
300
|
+
/**
|
301
|
+
* sock_listener(sa):
|
302
|
+
* Create a socket, set SO_REUSEADDR, bind it to the socket address ${sa},
|
303
|
+
* mark it for listening, and mark it as non-blocking.
|
304
|
+
*/
|
305
|
+
int
|
306
|
+
sock_listener(const struct sock_addr * sa)
|
307
|
+
{
|
308
|
+
int s;
|
309
|
+
int val = 1;
|
310
|
+
|
311
|
+
/* Create a socket. */
|
312
|
+
if ((s = socket(sa->ai_family, sa->ai_socktype, 0)) == -1) {
|
313
|
+
warnp("socket(%d, %d)", sa->ai_family, sa->ai_socktype);
|
314
|
+
goto err0;
|
315
|
+
}
|
316
|
+
|
317
|
+
/* Set SO_REUSEADDR. */
|
318
|
+
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) {
|
319
|
+
warnp("setsockopt(SO_REUSEADDR)");
|
320
|
+
goto err1;
|
321
|
+
}
|
322
|
+
|
323
|
+
/* Bind the socket. */
|
324
|
+
if (bind(s, sa->name, sa->namelen)) {
|
325
|
+
warnp("Error binding socket");
|
326
|
+
goto err1;
|
327
|
+
}
|
328
|
+
|
329
|
+
/* Mark the socket as listening. */
|
330
|
+
if (listen(s, 10)) {
|
331
|
+
warnp("Error marking socket as listening");
|
332
|
+
goto err1;
|
333
|
+
}
|
334
|
+
|
335
|
+
/* Mark the socket as non-blocking. */
|
336
|
+
if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
|
337
|
+
warnp("Error marking socket as non-blocking");
|
338
|
+
goto err1;
|
339
|
+
}
|
340
|
+
|
341
|
+
/* Success! */
|
342
|
+
return (s);
|
343
|
+
|
344
|
+
err1:
|
345
|
+
close(s);
|
346
|
+
err0:
|
347
|
+
/* Failure! */
|
348
|
+
return (-1);
|
349
|
+
}
|
350
|
+
|
351
|
+
/**
|
352
|
+
* sock_connect(sas):
|
353
|
+
* Iterate through the addresses in ${sas}, attempting to create a socket and
|
354
|
+
* connect (blockingly). Once connected, stop iterating, mark the socket as
|
355
|
+
* non-blocking, and return it.
|
356
|
+
*/
|
357
|
+
int
|
358
|
+
sock_connect(struct sock_addr * const * sas)
|
359
|
+
{
|
360
|
+
int s = -1;
|
361
|
+
|
362
|
+
/* Iterate through the addresses provided. */
|
363
|
+
for (; sas[0] != NULL; sas++) {
|
364
|
+
/* Create a socket. */
|
365
|
+
if ((s = socket(sas[0]->ai_family,
|
366
|
+
sas[0]->ai_socktype, 0)) == -1)
|
367
|
+
continue;
|
368
|
+
|
369
|
+
/* Attempt to connect. */
|
370
|
+
if (connect(s, sas[0]->name, sas[0]->namelen) == 0)
|
371
|
+
break;
|
372
|
+
|
373
|
+
/* Close the socket; this address didn't work. */
|
374
|
+
close(s);
|
375
|
+
}
|
376
|
+
|
377
|
+
/* Did we manage to connect? */
|
378
|
+
if (sas[0] == NULL) {
|
379
|
+
warn0("Could not connect");
|
380
|
+
goto err0;
|
381
|
+
}
|
382
|
+
|
383
|
+
/* Mark the socket as non-blocking. */
|
384
|
+
if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
|
385
|
+
warnp("Cannot make connection non-blocking");
|
386
|
+
goto err1;
|
387
|
+
}
|
388
|
+
|
389
|
+
/* Success! */
|
390
|
+
return (s);
|
391
|
+
|
392
|
+
err1:
|
393
|
+
close(s);
|
394
|
+
err0:
|
395
|
+
/* Failure! */
|
396
|
+
return (-1);
|
397
|
+
}
|
398
|
+
|
399
|
+
/**
|
400
|
+
* sock_connect_nb(sa):
|
401
|
+
* Create a socket, mark it as non-blocking, and attempt to connect to the
|
402
|
+
* address ${sa}. Return the socket (connected or in the process of
|
403
|
+
* connecting) or -1 on error.
|
404
|
+
*/
|
405
|
+
int
|
406
|
+
sock_connect_nb(const struct sock_addr * sa)
|
407
|
+
{
|
408
|
+
int s;
|
409
|
+
|
410
|
+
/* Create a socket. */
|
411
|
+
if ((s = socket(sa->ai_family, sa->ai_socktype, 0)) == -1)
|
412
|
+
goto err0;
|
413
|
+
|
414
|
+
/* Mark the socket as non-blocking. */
|
415
|
+
if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
|
416
|
+
warnp("Cannot make socket non-blocking");
|
417
|
+
goto err1;
|
418
|
+
}
|
419
|
+
|
420
|
+
/* Attempt to connect. */
|
421
|
+
if ((connect(s, sa->name, sa->namelen) == -1) &&
|
422
|
+
(errno != EINPROGRESS) &&
|
423
|
+
(errno != EINTR))
|
424
|
+
goto err1;
|
425
|
+
|
426
|
+
/* We have a connect(ed|ing) socket. */
|
427
|
+
return (s);
|
428
|
+
|
429
|
+
err1:
|
430
|
+
close(s);
|
431
|
+
err0:
|
432
|
+
/* We failed to connect to this address. */
|
433
|
+
return (-1);
|
434
|
+
}
|
435
|
+
|
436
|
+
/**
|
437
|
+
* sock_addr_free(sa):
|
438
|
+
* Free the provided sock_addr structure.
|
439
|
+
*/
|
440
|
+
void
|
441
|
+
sock_addr_free(struct sock_addr * sa)
|
442
|
+
{
|
443
|
+
|
444
|
+
/* Compatibility with free(NULL). */
|
445
|
+
if (sa == NULL)
|
446
|
+
return;
|
447
|
+
|
448
|
+
/* Free the protocol-specific address structure and our struct. */
|
449
|
+
free(sa->name);
|
450
|
+
free(sa);
|
451
|
+
}
|
452
|
+
|
453
|
+
/**
|
454
|
+
* sock_addr_freelist(sas):
|
455
|
+
* Free the provided NULL-terminated array of sock_addr structures.
|
456
|
+
*/
|
457
|
+
void
|
458
|
+
sock_addr_freelist(struct sock_addr ** sas)
|
459
|
+
{
|
460
|
+
struct sock_addr ** p;
|
461
|
+
|
462
|
+
/* Compatibility with free(NULL). */
|
463
|
+
if (sas == NULL)
|
464
|
+
return;
|
465
|
+
|
466
|
+
/* Free structures until we hit NULL. */
|
467
|
+
for (p = sas; *p != NULL; p++)
|
468
|
+
sock_addr_free(*p);
|
469
|
+
|
470
|
+
/* Free the list. */
|
471
|
+
free(sas);
|
472
|
+
}
|