spiped 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}
|