mirror of
https://github.com/bol-van/zapret.git
synced 2025-05-24 22:32:58 +03:00
Linting and formatting of .c
and .h
with C/C++ IntelliSence
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
#ifndef SHIM_SYS_EPOLL_H
|
||||
#define SHIM_SYS_EPOLL_H
|
||||
#ifndef SHIM_SYS_EPOLL_H
|
||||
#define SHIM_SYS_EPOLL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -18,7 +19,10 @@ extern "C" {
|
||||
#define EPOLL_CLOEXEC O_CLOEXEC
|
||||
#define EPOLL_NONBLOCK O_NONBLOCK
|
||||
|
||||
enum EPOLL_EVENTS { __EPOLL_DUMMY };
|
||||
enum EPOLL_EVENTS
|
||||
{
|
||||
__EPOLL_DUMMY
|
||||
};
|
||||
#define EPOLLIN 0x001
|
||||
#define EPOLLPRI 0x002
|
||||
#define EPOLLOUT 0x004
|
||||
@@ -31,48 +35,47 @@ enum EPOLL_EVENTS { __EPOLL_DUMMY };
|
||||
#define EPOLLERR 0x008
|
||||
#define EPOLLHUP 0x010
|
||||
#define EPOLLRDHUP 0x2000
|
||||
#define EPOLLEXCLUSIVE (1U<<28)
|
||||
#define EPOLLWAKEUP (1U<<29)
|
||||
#define EPOLLONESHOT (1U<<30)
|
||||
#define EPOLLET (1U<<31)
|
||||
#define EPOLLEXCLUSIVE (1U << 28)
|
||||
#define EPOLLWAKEUP (1U << 29)
|
||||
#define EPOLLONESHOT (1U << 30)
|
||||
#define EPOLLET (1U << 31)
|
||||
|
||||
#define EPOLL_CTL_ADD 1
|
||||
#define EPOLL_CTL_DEL 2
|
||||
#define EPOLL_CTL_MOD 3
|
||||
|
||||
typedef union epoll_data {
|
||||
void *ptr;
|
||||
int fd;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
} epoll_data_t;
|
||||
typedef union epoll_data
|
||||
{
|
||||
void *ptr;
|
||||
int fd;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
} epoll_data_t;
|
||||
|
||||
struct epoll_event {
|
||||
uint32_t events;
|
||||
epoll_data_t data;
|
||||
}
|
||||
struct epoll_event
|
||||
{
|
||||
uint32_t events;
|
||||
epoll_data_t data;
|
||||
}
|
||||
#ifdef __x86_64__
|
||||
__attribute__ ((__packed__))
|
||||
__attribute__((__packed__))
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
int epoll_create(int);
|
||||
int epoll_create1(int);
|
||||
int epoll_ctl(int, int, int, struct epoll_event *);
|
||||
int epoll_wait(int, struct epoll_event *, int, int);
|
||||
int epoll_pwait(int, struct epoll_event *, int, int, const sigset_t *);
|
||||
;
|
||||
|
||||
int epoll_create(int);
|
||||
int epoll_create1(int);
|
||||
int epoll_ctl(int, int, int, struct epoll_event *);
|
||||
int epoll_wait(int, struct epoll_event *, int, int);
|
||||
int epoll_pwait(int, struct epoll_event *, int, int, const sigset_t *);
|
||||
|
||||
#ifndef SHIM_SYS_SHIM_HELPERS
|
||||
#define SHIM_SYS_SHIM_HELPERS
|
||||
#include <unistd.h> /* IWYU pragma: keep */
|
||||
|
||||
extern int epoll_shim_close(int);
|
||||
extern int epoll_shim_close(int);
|
||||
#define close epoll_shim_close
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -21,14 +21,16 @@
|
||||
// TODO(jan): Remove this once the definition is exposed in <sys/time.h> in
|
||||
// all supported FreeBSD versions.
|
||||
#ifndef timespecsub
|
||||
#define timespecsub(tsp, usp, vsp) \
|
||||
do { \
|
||||
(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
|
||||
(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
|
||||
if ((vsp)->tv_nsec < 0) { \
|
||||
(vsp)->tv_sec--; \
|
||||
(vsp)->tv_nsec += 1000000000L; \
|
||||
} \
|
||||
#define timespecsub(tsp, usp, vsp) \
|
||||
do \
|
||||
{ \
|
||||
(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
|
||||
(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
|
||||
if ((vsp)->tv_nsec < 0) \
|
||||
{ \
|
||||
(vsp)->tv_sec--; \
|
||||
(vsp)->tv_nsec += 1000000000L; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
@@ -39,9 +41,9 @@ epollfd_close(FDContextMapNode *node)
|
||||
}
|
||||
|
||||
static FDContextVTable const epollfd_vtable = {
|
||||
.read_fun = fd_context_default_read,
|
||||
.write_fun = fd_context_default_write,
|
||||
.close_fun = epollfd_close,
|
||||
.read_fun = fd_context_default_read,
|
||||
.write_fun = fd_context_default_write,
|
||||
.close_fun = epollfd_close,
|
||||
};
|
||||
|
||||
static FDContextMapNode *
|
||||
@@ -50,14 +52,16 @@ epoll_create_impl(errno_t *ec)
|
||||
FDContextMapNode *node;
|
||||
|
||||
node = epoll_shim_ctx_create_node(&epoll_shim_ctx, ec);
|
||||
if (!node) {
|
||||
if (!node)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
node->flags = 0;
|
||||
|
||||
if ((*ec = epollfd_ctx_init(&node->ctx.epollfd, /**/
|
||||
node->fd)) != 0) {
|
||||
node->fd)) != 0)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -77,7 +81,8 @@ epoll_create_common(void)
|
||||
errno_t ec;
|
||||
|
||||
node = epoll_create_impl(&ec);
|
||||
if (!node) {
|
||||
if (!node)
|
||||
{
|
||||
errno = ec;
|
||||
return -1;
|
||||
}
|
||||
@@ -85,10 +90,10 @@ epoll_create_common(void)
|
||||
return node->fd;
|
||||
}
|
||||
|
||||
int
|
||||
epoll_create(int size)
|
||||
int epoll_create(int size)
|
||||
{
|
||||
if (size <= 0) {
|
||||
if (size <= 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@@ -96,10 +101,10 @@ epoll_create(int size)
|
||||
return epoll_create_common();
|
||||
}
|
||||
|
||||
int
|
||||
epoll_create1(int flags)
|
||||
int epoll_create1(int flags)
|
||||
{
|
||||
if (flags & ~EPOLL_CLOEXEC) {
|
||||
if (flags & ~EPOLL_CLOEXEC)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@@ -110,12 +115,14 @@ epoll_create1(int flags)
|
||||
static errno_t
|
||||
epoll_ctl_impl(int fd, int op, int fd2, struct epoll_event *ev)
|
||||
{
|
||||
if (!ev && op != EPOLL_CTL_DEL) {
|
||||
if (!ev && op != EPOLL_CTL_DEL)
|
||||
{
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
|
||||
if (!node || node->vtable != &epollfd_vtable) {
|
||||
if (!node || node->vtable != &epollfd_vtable)
|
||||
{
|
||||
struct stat sb;
|
||||
return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL;
|
||||
}
|
||||
@@ -123,11 +130,11 @@ epoll_ctl_impl(int fd, int op, int fd2, struct epoll_event *ev)
|
||||
return epollfd_ctx_ctl(&node->ctx.epollfd, op, fd2, ev);
|
||||
}
|
||||
|
||||
int
|
||||
epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
|
||||
int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
|
||||
{
|
||||
errno_t ec = epoll_ctl_impl(fd, op, fd2, ev);
|
||||
if (ec != 0) {
|
||||
if (ec != 0)
|
||||
{
|
||||
errno = ec;
|
||||
return -1;
|
||||
}
|
||||
@@ -143,33 +150,39 @@ is_no_wait_deadline(struct timespec const *deadline)
|
||||
|
||||
static errno_t
|
||||
epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
|
||||
int *actual_cnt, struct timespec const *deadline, sigset_t const *sigs)
|
||||
int *actual_cnt, struct timespec const *deadline, sigset_t const *sigs)
|
||||
{
|
||||
errno_t ec;
|
||||
|
||||
for (;;) {
|
||||
for (;;)
|
||||
{
|
||||
if ((ec = epollfd_ctx_wait(epollfd, /**/
|
||||
ev, cnt, actual_cnt)) != 0) {
|
||||
ev, cnt, actual_cnt)) != 0)
|
||||
{
|
||||
return ec;
|
||||
}
|
||||
|
||||
if (*actual_cnt || is_no_wait_deadline(deadline)) {
|
||||
if (*actual_cnt || is_no_wait_deadline(deadline))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct timespec timeout;
|
||||
|
||||
if (deadline) {
|
||||
if (deadline)
|
||||
{
|
||||
struct timespec current_time;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, /**/
|
||||
¤t_time) < 0) {
|
||||
¤t_time) < 0)
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
timespecsub(deadline, ¤t_time, &timeout);
|
||||
if (timeout.tv_sec < 0 ||
|
||||
is_no_wait_deadline(&timeout)) {
|
||||
is_no_wait_deadline(&timeout))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -180,14 +193,16 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
|
||||
|
||||
size_t size;
|
||||
if (__builtin_mul_overflow(nfds, sizeof(struct pollfd),
|
||||
&size)) {
|
||||
&size))
|
||||
{
|
||||
ec = ENOMEM;
|
||||
(void)pthread_mutex_unlock(&epollfd->mutex);
|
||||
return ec;
|
||||
}
|
||||
|
||||
struct pollfd *pfds = malloc(size);
|
||||
if (!pfds) {
|
||||
if (!pfds)
|
||||
{
|
||||
ec = errno;
|
||||
(void)pthread_mutex_unlock(&epollfd->mutex);
|
||||
return ec;
|
||||
@@ -211,7 +226,8 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
|
||||
#endif
|
||||
|
||||
int n = ppoll(pfds, nfds, deadline ? &timeout : NULL, sigs);
|
||||
if (n < 0) {
|
||||
if (n < 0)
|
||||
{
|
||||
ec = errno;
|
||||
}
|
||||
|
||||
@@ -219,13 +235,15 @@ epollfd_ctx_wait_or_block(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
|
||||
|
||||
(void)pthread_mutex_lock(&epollfd->nr_polling_threads_mutex);
|
||||
--epollfd->nr_polling_threads;
|
||||
if (epollfd->nr_polling_threads == 0) {
|
||||
if (epollfd->nr_polling_threads == 0)
|
||||
{
|
||||
(void)pthread_cond_signal(
|
||||
&epollfd->nr_polling_threads_cond);
|
||||
&epollfd->nr_polling_threads_cond);
|
||||
}
|
||||
(void)pthread_mutex_unlock(&epollfd->nr_polling_threads_mutex);
|
||||
|
||||
if (n < 0) {
|
||||
if (n < 0)
|
||||
{
|
||||
return ec;
|
||||
}
|
||||
}
|
||||
@@ -236,21 +254,27 @@ timeout_to_deadline(struct timespec *deadline, int to)
|
||||
{
|
||||
assert(to >= 0);
|
||||
|
||||
if (to == 0) {
|
||||
if (to == 0)
|
||||
{
|
||||
*deadline = (struct timespec){0, 0};
|
||||
} else if (to > 0) {
|
||||
if (clock_gettime(CLOCK_MONOTONIC, deadline) < 0) {
|
||||
}
|
||||
else if (to > 0)
|
||||
{
|
||||
if (clock_gettime(CLOCK_MONOTONIC, deadline) < 0)
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
if (__builtin_add_overflow(deadline->tv_sec, to / 1000 + 1,
|
||||
&deadline->tv_sec)) {
|
||||
&deadline->tv_sec))
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
deadline->tv_sec -= 1;
|
||||
|
||||
deadline->tv_nsec += (to % 1000) * 1000000L;
|
||||
if (deadline->tv_nsec >= 1000000000) {
|
||||
if (deadline->tv_nsec >= 1000000000)
|
||||
{
|
||||
deadline->tv_nsec -= 1000000000;
|
||||
deadline->tv_sec += 1;
|
||||
}
|
||||
@@ -261,36 +285,39 @@ timeout_to_deadline(struct timespec *deadline, int to)
|
||||
|
||||
static errno_t
|
||||
epoll_pwait_impl(int fd, struct epoll_event *ev, int cnt, int to,
|
||||
sigset_t const *sigs, int *actual_cnt)
|
||||
sigset_t const *sigs, int *actual_cnt)
|
||||
{
|
||||
if (cnt < 1 || cnt > (int)(INT_MAX / sizeof(struct epoll_event))) {
|
||||
if (cnt < 1 || cnt > (int)(INT_MAX / sizeof(struct epoll_event)))
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
FDContextMapNode *node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
|
||||
if (!node || node->vtable != &epollfd_vtable) {
|
||||
if (!node || node->vtable != &epollfd_vtable)
|
||||
{
|
||||
struct stat sb;
|
||||
return (fd < 0 || fstat(fd, &sb) < 0) ? EBADF : EINVAL;
|
||||
}
|
||||
|
||||
struct timespec deadline;
|
||||
errno_t ec;
|
||||
if (to >= 0 && (ec = timeout_to_deadline(&deadline, to)) != 0) {
|
||||
if (to >= 0 && (ec = timeout_to_deadline(&deadline, to)) != 0)
|
||||
{
|
||||
return ec;
|
||||
}
|
||||
|
||||
return epollfd_ctx_wait_or_block(&node->ctx.epollfd, ev, cnt,
|
||||
actual_cnt, (to >= 0) ? &deadline : NULL, sigs);
|
||||
actual_cnt, (to >= 0) ? &deadline : NULL, sigs);
|
||||
}
|
||||
|
||||
int
|
||||
epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to,
|
||||
sigset_t const *sigs)
|
||||
int epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to,
|
||||
sigset_t const *sigs)
|
||||
{
|
||||
int actual_cnt;
|
||||
|
||||
errno_t ec = epoll_pwait_impl(fd, ev, cnt, to, sigs, &actual_cnt);
|
||||
if (ec != 0) {
|
||||
if (ec != 0)
|
||||
{
|
||||
errno = ec;
|
||||
return -1;
|
||||
}
|
||||
@@ -298,8 +325,7 @@ epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to,
|
||||
return actual_cnt;
|
||||
}
|
||||
|
||||
int
|
||||
epoll_wait(int fd, struct epoll_event *ev, int cnt, int to)
|
||||
int epoll_wait(int fd, struct epoll_event *ev, int cnt, int to)
|
||||
{
|
||||
return epoll_pwait(fd, ev, cnt, to, NULL);
|
||||
}
|
||||
|
@@ -20,7 +20,8 @@ fd_context_map_node_create(int kq, errno_t *ec)
|
||||
FDContextMapNode *node;
|
||||
|
||||
node = malloc(sizeof(FDContextMapNode));
|
||||
if (!node) {
|
||||
if (!node)
|
||||
{
|
||||
*ec = errno;
|
||||
return NULL;
|
||||
}
|
||||
@@ -34,7 +35,8 @@ fd_context_map_node_terminate(FDContextMapNode *node, bool close_fd)
|
||||
{
|
||||
errno_t ec = node->vtable ? node->vtable->close_fun(node) : 0;
|
||||
|
||||
if (close_fd && close(node->fd) < 0) {
|
||||
if (close_fd && close(node->fd) < 0)
|
||||
{
|
||||
ec = ec ? ec : errno;
|
||||
}
|
||||
|
||||
@@ -53,7 +55,7 @@ fd_context_map_node_destroy(FDContextMapNode *node)
|
||||
|
||||
errno_t
|
||||
fd_context_default_read(FDContextMapNode *node, /**/
|
||||
void *buf, size_t nbytes, size_t *bytes_transferred)
|
||||
void *buf, size_t nbytes, size_t *bytes_transferred)
|
||||
{
|
||||
(void)node;
|
||||
(void)buf;
|
||||
@@ -65,7 +67,7 @@ fd_context_default_read(FDContextMapNode *node, /**/
|
||||
|
||||
errno_t
|
||||
fd_context_default_write(FDContextMapNode *node, /**/
|
||||
void const *buf, size_t nbytes, size_t *bytes_transferred)
|
||||
void const *buf, size_t nbytes, size_t *bytes_transferred)
|
||||
{
|
||||
(void)node;
|
||||
(void)buf;
|
||||
@@ -84,18 +86,18 @@ fd_context_map_node_cmp(FDContextMapNode *e1, FDContextMapNode *e2)
|
||||
}
|
||||
|
||||
RB_PROTOTYPE_STATIC(fd_context_map_, fd_context_map_node_, entry,
|
||||
fd_context_map_node_cmp);
|
||||
fd_context_map_node_cmp);
|
||||
RB_GENERATE_STATIC(fd_context_map_, fd_context_map_node_, entry,
|
||||
fd_context_map_node_cmp);
|
||||
fd_context_map_node_cmp);
|
||||
|
||||
EpollShimCtx epoll_shim_ctx = {
|
||||
.fd_context_map = RB_INITIALIZER(&fd_context_map),
|
||||
.mutex = PTHREAD_MUTEX_INITIALIZER,
|
||||
.fd_context_map = RB_INITIALIZER(&fd_context_map),
|
||||
.mutex = PTHREAD_MUTEX_INITIALIZER,
|
||||
};
|
||||
|
||||
static FDContextMapNode *
|
||||
epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq,
|
||||
errno_t *ec)
|
||||
errno_t *ec)
|
||||
{
|
||||
FDContextMapNode *node;
|
||||
|
||||
@@ -104,10 +106,11 @@ epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq,
|
||||
find.fd = kq;
|
||||
|
||||
node = RB_FIND(fd_context_map_, /**/
|
||||
&epoll_shim_ctx->fd_context_map, &find);
|
||||
&epoll_shim_ctx->fd_context_map, &find);
|
||||
}
|
||||
|
||||
if (node) {
|
||||
if (node)
|
||||
{
|
||||
/*
|
||||
* If we get here, someone must have already closed the old fd
|
||||
* with a normal 'close()' call, i.e. not with our
|
||||
@@ -118,14 +121,17 @@ epoll_shim_ctx_create_node_impl(EpollShimCtx *epoll_shim_ctx, int kq,
|
||||
*/
|
||||
(void)fd_context_map_node_terminate(node, false);
|
||||
fd_context_map_node_init(node, kq);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
node = fd_context_map_node_create(kq, ec);
|
||||
if (!node) {
|
||||
if (!node)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *colliding_node = RB_INSERT(fd_context_map_,
|
||||
&epoll_shim_ctx->fd_context_map, node);
|
||||
&epoll_shim_ctx->fd_context_map, node);
|
||||
(void)colliding_node;
|
||||
assert(colliding_node == NULL);
|
||||
}
|
||||
@@ -139,7 +145,8 @@ epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx, errno_t *ec)
|
||||
FDContextMapNode *node;
|
||||
|
||||
int kq = kqueue();
|
||||
if (kq < 0) {
|
||||
if (kq < 0)
|
||||
{
|
||||
*ec = errno;
|
||||
return NULL;
|
||||
}
|
||||
@@ -148,7 +155,8 @@ epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx, errno_t *ec)
|
||||
node = epoll_shim_ctx_create_node_impl(epoll_shim_ctx, kq, ec);
|
||||
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
|
||||
|
||||
if (!node) {
|
||||
if (!node)
|
||||
{
|
||||
close(kq);
|
||||
}
|
||||
|
||||
@@ -164,7 +172,7 @@ epoll_shim_ctx_find_node_impl(EpollShimCtx *epoll_shim_ctx, int fd)
|
||||
find.fd = fd;
|
||||
|
||||
node = RB_FIND(fd_context_map_, /**/
|
||||
&epoll_shim_ctx->fd_context_map, &find);
|
||||
&epoll_shim_ctx->fd_context_map, &find);
|
||||
|
||||
return node;
|
||||
}
|
||||
@@ -188,39 +196,40 @@ epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx, int fd)
|
||||
|
||||
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
|
||||
node = epoll_shim_ctx_find_node_impl(epoll_shim_ctx, fd);
|
||||
if (node) {
|
||||
if (node)
|
||||
{
|
||||
RB_REMOVE(fd_context_map_, /**/
|
||||
&epoll_shim_ctx->fd_context_map, node);
|
||||
&epoll_shim_ctx->fd_context_map, node);
|
||||
}
|
||||
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void
|
||||
epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
|
||||
FDContextMapNode *node)
|
||||
void epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
|
||||
FDContextMapNode *node)
|
||||
{
|
||||
(void)pthread_mutex_lock(&epoll_shim_ctx->mutex);
|
||||
RB_REMOVE(fd_context_map_, /**/
|
||||
&epoll_shim_ctx->fd_context_map, node);
|
||||
&epoll_shim_ctx->fd_context_map, node);
|
||||
(void)pthread_mutex_unlock(&epoll_shim_ctx->mutex);
|
||||
}
|
||||
|
||||
/**/
|
||||
|
||||
int
|
||||
epoll_shim_close(int fd)
|
||||
int epoll_shim_close(int fd)
|
||||
{
|
||||
FDContextMapNode *node;
|
||||
|
||||
node = epoll_shim_ctx_remove_node(&epoll_shim_ctx, fd);
|
||||
if (!node) {
|
||||
if (!node)
|
||||
{
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
errno_t ec = fd_context_map_node_destroy(node);
|
||||
if (ec != 0) {
|
||||
if (ec != 0)
|
||||
{
|
||||
errno = ec;
|
||||
return -1;
|
||||
}
|
||||
@@ -234,19 +243,22 @@ epoll_shim_read(int fd, void *buf, size_t nbytes)
|
||||
FDContextMapNode *node;
|
||||
|
||||
node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
|
||||
if (!node) {
|
||||
if (!node)
|
||||
{
|
||||
return read(fd, buf, nbytes);
|
||||
}
|
||||
|
||||
if (nbytes > SSIZE_MAX) {
|
||||
if (nbytes > SSIZE_MAX)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t bytes_transferred;
|
||||
errno_t ec = node->vtable->read_fun(node, /**/
|
||||
buf, nbytes, &bytes_transferred);
|
||||
if (ec != 0) {
|
||||
buf, nbytes, &bytes_transferred);
|
||||
if (ec != 0)
|
||||
{
|
||||
errno = ec;
|
||||
return -1;
|
||||
}
|
||||
@@ -260,19 +272,22 @@ epoll_shim_write(int fd, void const *buf, size_t nbytes)
|
||||
FDContextMapNode *node;
|
||||
|
||||
node = epoll_shim_ctx_find_node(&epoll_shim_ctx, fd);
|
||||
if (!node) {
|
||||
if (!node)
|
||||
{
|
||||
return write(fd, buf, nbytes);
|
||||
}
|
||||
|
||||
if (nbytes > SSIZE_MAX) {
|
||||
if (nbytes > SSIZE_MAX)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t bytes_transferred;
|
||||
errno_t ec = node->vtable->write_fun(node, /**/
|
||||
buf, nbytes, &bytes_transferred);
|
||||
if (ec != 0) {
|
||||
buf, nbytes, &bytes_transferred);
|
||||
if (ec != 0)
|
||||
{
|
||||
errno = ec;
|
||||
return -1;
|
||||
}
|
||||
|
@@ -16,27 +16,31 @@ struct fd_context_map_node_;
|
||||
typedef struct fd_context_map_node_ FDContextMapNode;
|
||||
|
||||
typedef errno_t (*fd_context_read_fun)(FDContextMapNode *node, /**/
|
||||
void *buf, size_t nbytes, size_t *bytes_transferred);
|
||||
void *buf, size_t nbytes, size_t *bytes_transferred);
|
||||
typedef errno_t (*fd_context_write_fun)(FDContextMapNode *node, /**/
|
||||
const void *buf, size_t nbytes, size_t *bytes_transferred);
|
||||
const void *buf, size_t nbytes, size_t *bytes_transferred);
|
||||
typedef errno_t (*fd_context_close_fun)(FDContextMapNode *node);
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
fd_context_read_fun read_fun;
|
||||
fd_context_write_fun write_fun;
|
||||
fd_context_close_fun close_fun;
|
||||
} FDContextVTable;
|
||||
|
||||
errno_t fd_context_default_read(FDContextMapNode *node, /**/
|
||||
void *buf, size_t nbytes, size_t *bytes_transferred);
|
||||
void *buf, size_t nbytes, size_t *bytes_transferred);
|
||||
errno_t fd_context_default_write(FDContextMapNode *node, /**/
|
||||
void const *buf, size_t nbytes, size_t *bytes_transferred);
|
||||
void const *buf, size_t nbytes, size_t *bytes_transferred);
|
||||
|
||||
struct fd_context_map_node_ {
|
||||
RB_ENTRY(fd_context_map_node_) entry;
|
||||
struct fd_context_map_node_
|
||||
{
|
||||
RB_ENTRY(fd_context_map_node_)
|
||||
entry;
|
||||
int fd;
|
||||
int flags;
|
||||
union {
|
||||
union
|
||||
{
|
||||
EpollFDCtx epollfd;
|
||||
EventFDCtx eventfd;
|
||||
TimerFDCtx timerfd;
|
||||
@@ -51,7 +55,8 @@ errno_t fd_context_map_node_destroy(FDContextMapNode *node);
|
||||
|
||||
typedef RB_HEAD(fd_context_map_, fd_context_map_node_) FDContextMap;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
FDContextMap fd_context_map;
|
||||
pthread_mutex_t mutex;
|
||||
} EpollShimCtx;
|
||||
@@ -59,13 +64,13 @@ typedef struct {
|
||||
extern EpollShimCtx epoll_shim_ctx;
|
||||
|
||||
FDContextMapNode *epoll_shim_ctx_create_node(EpollShimCtx *epoll_shim_ctx,
|
||||
errno_t *ec);
|
||||
errno_t *ec);
|
||||
FDContextMapNode *epoll_shim_ctx_find_node(EpollShimCtx *epoll_shim_ctx,
|
||||
int fd);
|
||||
int fd);
|
||||
FDContextMapNode *epoll_shim_ctx_remove_node(EpollShimCtx *epoll_shim_ctx,
|
||||
int fd);
|
||||
int fd);
|
||||
void epoll_shim_ctx_remove_node_explicit(EpollShimCtx *epoll_shim_ctx,
|
||||
FDContextMapNode *node);
|
||||
FDContextMapNode *node);
|
||||
|
||||
/**/
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -19,12 +19,14 @@
|
||||
struct registered_fds_node_;
|
||||
typedef struct registered_fds_node_ RegisteredFDsNode;
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
EOF_STATE_READ_EOF = 0x01,
|
||||
EOF_STATE_WRITE_EOF = 0x02,
|
||||
} EOFState;
|
||||
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
NODE_TYPE_FIFO = 1,
|
||||
NODE_TYPE_SOCKET = 2,
|
||||
NODE_TYPE_KQUEUE = 3,
|
||||
@@ -32,9 +34,12 @@ typedef enum {
|
||||
NODE_TYPE_POLL = 5,
|
||||
} NodeType;
|
||||
|
||||
struct registered_fds_node_ {
|
||||
RB_ENTRY(registered_fds_node_) entry;
|
||||
TAILQ_ENTRY(registered_fds_node_) pollfd_list_entry;
|
||||
struct registered_fds_node_
|
||||
{
|
||||
RB_ENTRY(registered_fds_node_)
|
||||
entry;
|
||||
TAILQ_ENTRY(registered_fds_node_)
|
||||
pollfd_list_entry;
|
||||
|
||||
int fd;
|
||||
epoll_data_t data;
|
||||
@@ -50,8 +55,10 @@ struct registered_fds_node_ {
|
||||
bool got_evfilt_except;
|
||||
|
||||
NodeType node_type;
|
||||
union {
|
||||
struct {
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
bool readable;
|
||||
bool writable;
|
||||
} fifo;
|
||||
@@ -72,7 +79,8 @@ struct registered_fds_node_ {
|
||||
typedef TAILQ_HEAD(pollfds_list_, registered_fds_node_) PollFDList;
|
||||
typedef RB_HEAD(registered_fds_set_, registered_fds_node_) RegisteredFDsSet;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
int kq; // non owning
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
@@ -101,8 +109,8 @@ errno_t epollfd_ctx_terminate(EpollFDCtx *epollfd);
|
||||
void epollfd_ctx_fill_pollfds(EpollFDCtx *epollfd, struct pollfd *pfds);
|
||||
|
||||
errno_t epollfd_ctx_ctl(EpollFDCtx *epollfd, int op, int fd2,
|
||||
struct epoll_event *ev);
|
||||
struct epoll_event *ev);
|
||||
errno_t epollfd_ctx_wait(EpollFDCtx *epollfd, struct epoll_event *ev, int cnt,
|
||||
int *actual_cnt);
|
||||
int *actual_cnt);
|
||||
|
||||
#endif
|
||||
|
@@ -11,7 +11,8 @@
|
||||
|
||||
#define EVENTFD_CTX_FLAG_SEMAPHORE (1 << 0)
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
int kq_; // non owning
|
||||
int flags_;
|
||||
pthread_mutex_t mutex_;
|
||||
@@ -22,7 +23,7 @@ typedef struct {
|
||||
} EventFDCtx;
|
||||
|
||||
errno_t eventfd_ctx_init(EventFDCtx *eventfd, int kq, unsigned int counter,
|
||||
int flags);
|
||||
int flags);
|
||||
errno_t eventfd_ctx_terminate(EventFDCtx *eventfd);
|
||||
|
||||
errno_t eventfd_ctx_write(EventFDCtx *eventfd, uint64_t value);
|
||||
|
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
int ppoll(struct pollfd *fds, nfds_t nfds,const struct timespec *tmo_p, const sigset_t *sigmask)
|
||||
int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask)
|
||||
{
|
||||
// macos does not implement ppoll
|
||||
// this is a hacky ppoll shim. only for tpws which does not require sigmask
|
||||
@@ -13,7 +13,7 @@ int ppoll(struct pollfd *fds, nfds_t nfds,const struct timespec *tmo_p, const si
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return poll(fds,nfds,tmo_p ? tmo_p->tv_sec*1000 + tmo_p->tv_nsec/1000000 : -1);
|
||||
return poll(fds, nfds, tmo_p ? tmo_p->tv_sec * 1000 + tmo_p->tv_nsec / 1000000 : -1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -11,10 +11,11 @@ typedef int errno_t;
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
|
||||
struct itimerspec {
|
||||
struct timespec it_interval;
|
||||
struct timespec it_value;
|
||||
struct itimerspec
|
||||
{
|
||||
struct timespec it_interval;
|
||||
struct timespec it_value;
|
||||
};
|
||||
int ppoll(struct pollfd *fds, nfds_t nfds,const struct timespec *tmo_p, const sigset_t *sigmask);
|
||||
int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigmask);
|
||||
|
||||
#endif
|
||||
|
@@ -7,7 +7,8 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
int kq; // non owning
|
||||
} SignalFDCtx;
|
||||
|
||||
|
@@ -11,7 +11,8 @@
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
int kq; // non owning
|
||||
int flags;
|
||||
pthread_mutex_t mutex;
|
||||
@@ -30,7 +31,7 @@ errno_t timerfd_ctx_init(TimerFDCtx *timerfd, int kq, int clockid);
|
||||
errno_t timerfd_ctx_terminate(TimerFDCtx *timerfd);
|
||||
|
||||
errno_t timerfd_ctx_settime(TimerFDCtx *timerfd, int flags,
|
||||
struct itimerspec const *new, struct itimerspec *old);
|
||||
struct itimerspec const *new, struct itimerspec *old);
|
||||
errno_t timerfd_ctx_gettime(TimerFDCtx *timerfd, struct itimerspec *cur);
|
||||
|
||||
errno_t timerfd_ctx_read(TimerFDCtx *timerfd, uint64_t *value);
|
||||
|
18
tpws/gzip.c
18
tpws/gzip.c
@@ -5,7 +5,7 @@
|
||||
|
||||
#define ZCHUNK 16384
|
||||
#define BUFMIN 128
|
||||
#define BUFCHUNK (1024*128)
|
||||
#define BUFCHUNK (1024 * 128)
|
||||
|
||||
int z_readfile(FILE *F, char **buf, size_t *size)
|
||||
{
|
||||
@@ -21,7 +21,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
||||
bufsize = *size = 0;
|
||||
|
||||
r = inflateInit2(&zs, 47);
|
||||
if (r != Z_OK) return r;
|
||||
if (r != Z_OK)
|
||||
return r;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -31,7 +32,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
||||
r = Z_ERRNO;
|
||||
goto zerr;
|
||||
}
|
||||
if (!zs.avail_in) break;
|
||||
if (!zs.avail_in)
|
||||
break;
|
||||
zs.next_in = in;
|
||||
do
|
||||
{
|
||||
@@ -47,9 +49,10 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
||||
*buf = newbuf;
|
||||
}
|
||||
zs.avail_out = bufsize - *size;
|
||||
zs.next_out = (unsigned char*)(*buf + *size);
|
||||
zs.next_out = (unsigned char *)(*buf + *size);
|
||||
r = inflate(&zs, Z_NO_FLUSH);
|
||||
if (r != Z_OK && r != Z_STREAM_END) goto zerr;
|
||||
if (r != Z_OK && r != Z_STREAM_END)
|
||||
goto zerr;
|
||||
*size = bufsize - zs.avail_out;
|
||||
} while (r == Z_OK && zs.avail_in);
|
||||
} while (r == Z_OK);
|
||||
@@ -57,7 +60,8 @@ int z_readfile(FILE *F, char **buf, size_t *size)
|
||||
if (*size < bufsize)
|
||||
{
|
||||
// free extra space
|
||||
if ((newbuf = realloc(*buf, *size))) *buf = newbuf;
|
||||
if ((newbuf = realloc(*buf, *size)))
|
||||
*buf = newbuf;
|
||||
}
|
||||
|
||||
inflateEnd(&zs);
|
||||
@@ -73,7 +77,7 @@ zerr:
|
||||
return r;
|
||||
}
|
||||
|
||||
bool is_gzip(FILE* F)
|
||||
bool is_gzip(FILE *F)
|
||||
{
|
||||
unsigned char magic[2];
|
||||
bool b = !fseek(F, 0, SEEK_SET) && fread(magic, 1, 2, F) == 2 && magic[0] == 0x1F && magic[1] == 0x8B;
|
||||
|
@@ -4,5 +4,5 @@
|
||||
#include <zlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
int z_readfile(FILE *F,char **buf,size_t *size);
|
||||
bool is_gzip(FILE* F);
|
||||
int z_readfile(FILE *F, char **buf, size_t *size);
|
||||
bool is_gzip(FILE *F);
|
||||
|
159
tpws/helpers.c
159
tpws/helpers.c
@@ -11,7 +11,7 @@
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
char *strncasestr(const char *s,const char *find, size_t slen)
|
||||
char *strncasestr(const char *s, const char *find, size_t slen)
|
||||
{
|
||||
char c, sc;
|
||||
size_t len;
|
||||
@@ -23,9 +23,11 @@ char *strncasestr(const char *s,const char *find, size_t slen)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (slen-- < 1 || (sc = *s++) == '\0') return NULL;
|
||||
if (slen-- < 1 || (sc = *s++) == '\0')
|
||||
return NULL;
|
||||
} while (toupper(c) != toupper(sc));
|
||||
if (len > slen) return NULL;
|
||||
if (len > slen)
|
||||
return NULL;
|
||||
} while (strncasecmp(s, find, len) != 0);
|
||||
s--;
|
||||
}
|
||||
@@ -34,71 +36,73 @@ char *strncasestr(const char *s,const char *find, size_t slen)
|
||||
|
||||
bool append_to_list_file(const char *filename, const char *s)
|
||||
{
|
||||
FILE *F = fopen(filename,"at");
|
||||
if (!F) return false;
|
||||
bool bOK = fprintf(F,"%s\n",s)>0;
|
||||
FILE *F = fopen(filename, "at");
|
||||
if (!F)
|
||||
return false;
|
||||
bool bOK = fprintf(F, "%s\n", s) > 0;
|
||||
fclose(F);
|
||||
return bOK;
|
||||
}
|
||||
|
||||
void ntop46(const struct sockaddr *sa, char *str, size_t len)
|
||||
{
|
||||
if (!len) return;
|
||||
*str=0;
|
||||
if (!len)
|
||||
return;
|
||||
*str = 0;
|
||||
switch (sa->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
inet_ntop(sa->sa_family, &((struct sockaddr_in*)sa)->sin_addr, str, len);
|
||||
inet_ntop(sa->sa_family, &((struct sockaddr_in *)sa)->sin_addr, str, len);
|
||||
break;
|
||||
case AF_INET6:
|
||||
inet_ntop(sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, str, len);
|
||||
inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)sa)->sin6_addr, str, len);
|
||||
break;
|
||||
default:
|
||||
snprintf(str,len,"UNKNOWN_FAMILY_%d",sa->sa_family);
|
||||
snprintf(str, len, "UNKNOWN_FAMILY_%d", sa->sa_family);
|
||||
}
|
||||
}
|
||||
void ntop46_port(const struct sockaddr *sa, char *str, size_t len)
|
||||
{
|
||||
char ip[40];
|
||||
ntop46(sa,ip,sizeof(ip));
|
||||
ntop46(sa, ip, sizeof(ip));
|
||||
switch (sa->sa_family)
|
||||
{
|
||||
case AF_INET:
|
||||
snprintf(str,len,"%s:%u",ip,ntohs(((struct sockaddr_in*)sa)->sin_port));
|
||||
snprintf(str, len, "%s:%u", ip, ntohs(((struct sockaddr_in *)sa)->sin_port));
|
||||
break;
|
||||
case AF_INET6:
|
||||
snprintf(str,len,"[%s]:%u",ip,ntohs(((struct sockaddr_in6*)sa)->sin6_port));
|
||||
snprintf(str, len, "[%s]:%u", ip, ntohs(((struct sockaddr_in6 *)sa)->sin6_port));
|
||||
break;
|
||||
default:
|
||||
snprintf(str,len,"%s",ip);
|
||||
snprintf(str, len, "%s", ip);
|
||||
}
|
||||
}
|
||||
void print_sockaddr(const struct sockaddr *sa)
|
||||
{
|
||||
char ip_port[48];
|
||||
|
||||
ntop46_port(sa,ip_port,sizeof(ip_port));
|
||||
printf("%s",ip_port);
|
||||
ntop46_port(sa, ip_port, sizeof(ip_port));
|
||||
printf("%s", ip_port);
|
||||
}
|
||||
|
||||
|
||||
// -1 = error, 0 = not local, 1 = local
|
||||
bool check_local_ip(const struct sockaddr *saddr)
|
||||
{
|
||||
struct ifaddrs *addrs,*a;
|
||||
struct ifaddrs *addrs, *a;
|
||||
|
||||
if (is_localnet(saddr))
|
||||
return true;
|
||||
|
||||
if (getifaddrs(&addrs)<0) return false;
|
||||
a = addrs;
|
||||
if (getifaddrs(&addrs) < 0)
|
||||
return false;
|
||||
a = addrs;
|
||||
|
||||
bool bres=false;
|
||||
bool bres = false;
|
||||
while (a)
|
||||
{
|
||||
if (a->ifa_addr && sacmp(a->ifa_addr,saddr))
|
||||
if (a->ifa_addr && sacmp(a->ifa_addr, saddr))
|
||||
{
|
||||
bres=true;
|
||||
bres = true;
|
||||
break;
|
||||
}
|
||||
a = a->ifa_next;
|
||||
@@ -115,50 +119,48 @@ void print_addrinfo(const struct addrinfo *ai)
|
||||
switch (ai->ai_family)
|
||||
{
|
||||
case AF_INET:
|
||||
if (inet_ntop(ai->ai_family, &((struct sockaddr_in*)ai->ai_addr)->sin_addr, str, sizeof(str)))
|
||||
if (inet_ntop(ai->ai_family, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, str, sizeof(str)))
|
||||
printf("%s\n", str);
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (inet_ntop(ai->ai_family, &((struct sockaddr_in6*)ai->ai_addr)->sin6_addr, str, sizeof(str)))
|
||||
printf( "%s\n", str);
|
||||
if (inet_ntop(ai->ai_family, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, str, sizeof(str)))
|
||||
printf("%s\n", str);
|
||||
break;
|
||||
}
|
||||
ai = ai->ai_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool saismapped(const struct sockaddr_in6 *sa)
|
||||
{
|
||||
// ::ffff:1.2.3.4
|
||||
return !memcmp(sa->sin6_addr.s6_addr,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff",12);
|
||||
return !memcmp(sa->sin6_addr.s6_addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff", 12);
|
||||
}
|
||||
bool samappedcmp(const struct sockaddr_in *sa1,const struct sockaddr_in6 *sa2)
|
||||
bool samappedcmp(const struct sockaddr_in *sa1, const struct sockaddr_in6 *sa2)
|
||||
{
|
||||
return saismapped(sa2) && !memcmp(sa2->sin6_addr.s6_addr+12,&sa1->sin_addr.s_addr,4);
|
||||
return saismapped(sa2) && !memcmp(sa2->sin6_addr.s6_addr + 12, &sa1->sin_addr.s_addr, 4);
|
||||
}
|
||||
bool sacmp(const struct sockaddr *sa1,const struct sockaddr *sa2)
|
||||
bool sacmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
|
||||
{
|
||||
return (sa1->sa_family==AF_INET && sa2->sa_family==AF_INET && !memcmp(&((struct sockaddr_in*)sa1)->sin_addr,&((struct sockaddr_in*)sa2)->sin_addr,sizeof(struct in_addr))) ||
|
||||
(sa1->sa_family==AF_INET6 && sa2->sa_family==AF_INET6 && !memcmp(&((struct sockaddr_in6*)sa1)->sin6_addr,&((struct sockaddr_in6*)sa2)->sin6_addr,sizeof(struct in6_addr))) ||
|
||||
(sa1->sa_family==AF_INET && sa2->sa_family==AF_INET6 && samappedcmp((struct sockaddr_in*)sa1,(struct sockaddr_in6*)sa2)) ||
|
||||
(sa1->sa_family==AF_INET6 && sa2->sa_family==AF_INET && samappedcmp((struct sockaddr_in*)sa2,(struct sockaddr_in6*)sa1));
|
||||
return (sa1->sa_family == AF_INET && sa2->sa_family == AF_INET && !memcmp(&((struct sockaddr_in *)sa1)->sin_addr, &((struct sockaddr_in *)sa2)->sin_addr, sizeof(struct in_addr))) ||
|
||||
(sa1->sa_family == AF_INET6 && sa2->sa_family == AF_INET6 && !memcmp(&((struct sockaddr_in6 *)sa1)->sin6_addr, &((struct sockaddr_in6 *)sa2)->sin6_addr, sizeof(struct in6_addr))) ||
|
||||
(sa1->sa_family == AF_INET && sa2->sa_family == AF_INET6 && samappedcmp((struct sockaddr_in *)sa1, (struct sockaddr_in6 *)sa2)) ||
|
||||
(sa1->sa_family == AF_INET6 && sa2->sa_family == AF_INET && samappedcmp((struct sockaddr_in *)sa2, (struct sockaddr_in6 *)sa1));
|
||||
}
|
||||
uint16_t saport(const struct sockaddr *sa)
|
||||
{
|
||||
return htons(sa->sa_family==AF_INET ? ((struct sockaddr_in*)sa)->sin_port :
|
||||
sa->sa_family==AF_INET6 ? ((struct sockaddr_in6*)sa)->sin6_port : 0);
|
||||
return htons(sa->sa_family == AF_INET ? ((struct sockaddr_in *)sa)->sin_port : sa->sa_family == AF_INET6 ? ((struct sockaddr_in6 *)sa)->sin6_port
|
||||
: 0);
|
||||
}
|
||||
bool saconvmapped(struct sockaddr_storage *a)
|
||||
{
|
||||
if ((a->ss_family == AF_INET6) && saismapped((struct sockaddr_in6*)a))
|
||||
if ((a->ss_family == AF_INET6) && saismapped((struct sockaddr_in6 *)a))
|
||||
{
|
||||
uint32_t ip4 = IN6_EXTRACT_MAP4(((struct sockaddr_in6*)a)->sin6_addr.s6_addr);
|
||||
uint16_t port = ((struct sockaddr_in6*)a)->sin6_port;
|
||||
uint32_t ip4 = IN6_EXTRACT_MAP4(((struct sockaddr_in6 *)a)->sin6_addr.s6_addr);
|
||||
uint16_t port = ((struct sockaddr_in6 *)a)->sin6_port;
|
||||
a->ss_family = AF_INET;
|
||||
((struct sockaddr_in*)a)->sin_addr.s_addr = ip4;
|
||||
((struct sockaddr_in*)a)->sin_port = port;
|
||||
((struct sockaddr_in *)a)->sin_addr.s_addr = ip4;
|
||||
((struct sockaddr_in *)a)->sin_port = port;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -167,45 +169,43 @@ bool saconvmapped(struct sockaddr_storage *a)
|
||||
bool is_localnet(const struct sockaddr *a)
|
||||
{
|
||||
// match 127.0.0.0/8, 0.0.0.0, ::1, ::0, :ffff:127.0.0.0/104, :ffff:0.0.0.0
|
||||
return (a->sa_family==AF_INET && (IN_LOOPBACK(ntohl(((struct sockaddr_in *)a)->sin_addr.s_addr)) ||
|
||||
INADDR_ANY == ntohl((((struct sockaddr_in *)a)->sin_addr.s_addr)))) ||
|
||||
(a->sa_family==AF_INET6 && (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)a)->sin6_addr) ||
|
||||
IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)a)->sin6_addr) ||
|
||||
(IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)a)->sin6_addr) && (IN_LOOPBACK(ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6*)a)->sin6_addr.s6_addr))) ||
|
||||
INADDR_ANY == ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6*)a)->sin6_addr.s6_addr))))));
|
||||
return (a->sa_family == AF_INET && (IN_LOOPBACK(ntohl(((struct sockaddr_in *)a)->sin_addr.s_addr)) ||
|
||||
INADDR_ANY == ntohl((((struct sockaddr_in *)a)->sin_addr.s_addr)))) ||
|
||||
(a->sa_family == AF_INET6 && (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)a)->sin6_addr) ||
|
||||
IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)a)->sin6_addr) ||
|
||||
(IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)a)->sin6_addr) && (IN_LOOPBACK(ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6 *)a)->sin6_addr.s6_addr))) ||
|
||||
INADDR_ANY == ntohl(IN6_EXTRACT_MAP4(((struct sockaddr_in6 *)a)->sin6_addr.s6_addr))))));
|
||||
}
|
||||
bool is_linklocal(const struct sockaddr_in6 *a)
|
||||
{
|
||||
// fe80::/10
|
||||
return a->sin6_addr.s6_addr[0]==0xFE && (a->sin6_addr.s6_addr[1] & 0xC0)==0x80;
|
||||
return a->sin6_addr.s6_addr[0] == 0xFE && (a->sin6_addr.s6_addr[1] & 0xC0) == 0x80;
|
||||
}
|
||||
bool is_private6(const struct sockaddr_in6* a)
|
||||
bool is_private6(const struct sockaddr_in6 *a)
|
||||
{
|
||||
// fc00::/7
|
||||
return (a->sin6_addr.s6_addr[0] & 0xFE) == 0xFC;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool set_keepalive(int fd)
|
||||
{
|
||||
int yes=1;
|
||||
return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int))!=-1;
|
||||
int yes = 1;
|
||||
return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(int)) != -1;
|
||||
}
|
||||
bool set_ttl(int fd, int ttl)
|
||||
{
|
||||
return setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))!=-1;
|
||||
return setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) != -1;
|
||||
}
|
||||
bool set_hl(int fd, int hl)
|
||||
{
|
||||
return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hl, sizeof(hl))!=-1;
|
||||
return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hl, sizeof(hl)) != -1;
|
||||
}
|
||||
bool set_ttl_hl(int fd, int ttl)
|
||||
{
|
||||
bool b1,b2;
|
||||
bool b1, b2;
|
||||
// try to set both but one may fail if family is wrong
|
||||
b1=set_ttl(fd, ttl);
|
||||
b2=set_hl(fd, ttl);
|
||||
b1 = set_ttl(fd, ttl);
|
||||
b2 = set_hl(fd, ttl);
|
||||
return b1 || b2;
|
||||
}
|
||||
int get_so_error(int fd)
|
||||
@@ -213,8 +213,8 @@ int get_so_error(int fd)
|
||||
// getsockopt(SO_ERROR) clears error
|
||||
int errn;
|
||||
socklen_t optlen = sizeof(errn);
|
||||
if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &errn, &optlen) == -1)
|
||||
errn=errno;
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errn, &optlen) == -1)
|
||||
errn = errno;
|
||||
return errn;
|
||||
}
|
||||
|
||||
@@ -224,42 +224,45 @@ int fprint_localtime(FILE *F)
|
||||
time_t now;
|
||||
|
||||
time(&now);
|
||||
localtime_r(&now,&t);
|
||||
localtime_r(&now, &t);
|
||||
return fprintf(F, "%02d.%02d.%04d %02d:%02d:%02d", t.tm_mday, t.tm_mon + 1, t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec);
|
||||
}
|
||||
|
||||
time_t file_mod_time(const char *filename)
|
||||
{
|
||||
struct stat st;
|
||||
return stat(filename,&st)==-1 ? 0 : st.st_mtime;
|
||||
return stat(filename, &st) == -1 ? 0 : st.st_mtime;
|
||||
}
|
||||
|
||||
bool pf_in_range(uint16_t port, const port_filter *pf)
|
||||
{
|
||||
return port && (((!pf->from && !pf->to) || (port>=pf->from && port<=pf->to)) ^ pf->neg);
|
||||
return port && (((!pf->from && !pf->to) || (port >= pf->from && port <= pf->to)) ^ pf->neg);
|
||||
}
|
||||
bool pf_parse(const char *s, port_filter *pf)
|
||||
{
|
||||
unsigned int v1,v2;
|
||||
unsigned int v1, v2;
|
||||
|
||||
if (!s) return false;
|
||||
if (*s=='~')
|
||||
if (!s)
|
||||
return false;
|
||||
if (*s == '~')
|
||||
{
|
||||
pf->neg=true;
|
||||
pf->neg = true;
|
||||
s++;
|
||||
}
|
||||
else
|
||||
pf->neg=false;
|
||||
if (sscanf(s,"%u-%u",&v1,&v2)==2)
|
||||
pf->neg = false;
|
||||
if (sscanf(s, "%u-%u", &v1, &v2) == 2)
|
||||
{
|
||||
if (!v1 || v1>65535 || v2>65535 || v1>v2) return false;
|
||||
pf->from=(uint16_t)v1;
|
||||
pf->to=(uint16_t)v2;
|
||||
if (!v1 || v1 > 65535 || v2 > 65535 || v1 > v2)
|
||||
return false;
|
||||
pf->from = (uint16_t)v1;
|
||||
pf->to = (uint16_t)v2;
|
||||
}
|
||||
else if (sscanf(s,"%u",&v1)==1)
|
||||
else if (sscanf(s, "%u", &v1) == 1)
|
||||
{
|
||||
if (!v1 || v1>65535) return false;
|
||||
pf->to=pf->from=(uint16_t)v1;
|
||||
if (!v1 || v1 > 65535)
|
||||
return false;
|
||||
pf->to = pf->from = (uint16_t)v1;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
@@ -8,7 +8,7 @@
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
char *strncasestr(const char *s,const char *find, size_t slen);
|
||||
char *strncasestr(const char *s, const char *find, size_t slen);
|
||||
|
||||
bool append_to_list_file(const char *filename, const char *s);
|
||||
|
||||
@@ -19,15 +19,15 @@ void print_addrinfo(const struct addrinfo *ai);
|
||||
bool check_local_ip(const struct sockaddr *saddr);
|
||||
|
||||
bool saismapped(const struct sockaddr_in6 *sa);
|
||||
bool samappedcmp(const struct sockaddr_in *sa1,const struct sockaddr_in6 *sa2);
|
||||
bool sacmp(const struct sockaddr *sa1,const struct sockaddr *sa2);
|
||||
bool samappedcmp(const struct sockaddr_in *sa1, const struct sockaddr_in6 *sa2);
|
||||
bool sacmp(const struct sockaddr *sa1, const struct sockaddr *sa2);
|
||||
uint16_t saport(const struct sockaddr *sa);
|
||||
// true = was converted
|
||||
bool saconvmapped(struct sockaddr_storage *a);
|
||||
|
||||
bool is_localnet(const struct sockaddr *a);
|
||||
bool is_linklocal(const struct sockaddr_in6* a);
|
||||
bool is_private6(const struct sockaddr_in6* a);
|
||||
bool is_linklocal(const struct sockaddr_in6 *a);
|
||||
bool is_private6(const struct sockaddr_in6 *a);
|
||||
|
||||
bool set_keepalive(int fd);
|
||||
bool set_ttl(int fd, int ttl);
|
||||
@@ -36,11 +36,13 @@ bool set_ttl_hl(int fd, int ttl);
|
||||
int get_so_error(int fd);
|
||||
|
||||
// alignment-safe functions
|
||||
static inline uint16_t pntoh16(const uint8_t *p) {
|
||||
static inline uint16_t pntoh16(const uint8_t *p)
|
||||
{
|
||||
return ((uint16_t)p[0] << 8) | (uint16_t)p[1];
|
||||
}
|
||||
static inline void phton16(uint8_t *p, uint16_t v) {
|
||||
p[0] = (uint8_t)(v>>8);
|
||||
static inline void phton16(uint8_t *p, uint16_t v)
|
||||
{
|
||||
p[0] = (uint8_t)(v >> 8);
|
||||
p[1] = (uint8_t)v;
|
||||
}
|
||||
|
||||
@@ -50,21 +52,20 @@ time_t file_mod_time(const char *filename);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t from,to;
|
||||
uint16_t from, to;
|
||||
bool neg;
|
||||
} port_filter;
|
||||
bool pf_in_range(uint16_t port, const port_filter *pf);
|
||||
bool pf_parse(const char *s, port_filter *pf);
|
||||
|
||||
#ifndef IN_LOOPBACK
|
||||
#define IN_LOOPBACK(a) ((((uint32_t) (a)) & 0xff000000) == 0x7f000000)
|
||||
#define IN_LOOPBACK(a) ((((uint32_t)(a)) & 0xff000000) == 0x7f000000)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define IN6_EXTRACT_MAP4(a) \
|
||||
(__extension__ \
|
||||
({ const struct in6_addr *__a = (const struct in6_addr *) (a); \
|
||||
(__extension__({ const struct in6_addr *__a = (const struct in6_addr *) (a); \
|
||||
(((const uint32_t *) (__a))[3]); }))
|
||||
#else
|
||||
#define IN6_EXTRACT_MAP4(a) (((const uint32_t *) (a))[3])
|
||||
#define IN6_EXTRACT_MAP4(a) (((const uint32_t *)(a))[3])
|
||||
#endif
|
||||
|
@@ -8,17 +8,19 @@
|
||||
static bool addpool(strpool **hostlist, char **s, const char *end)
|
||||
{
|
||||
char *p;
|
||||
|
||||
|
||||
// advance until eol lowering all chars
|
||||
for (p = *s; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
|
||||
if (!StrPoolAddStrLen(hostlist, *s, p-*s))
|
||||
for (p = *s; p < end && *p && *p != '\r' && *p != '\n'; p++)
|
||||
*p = tolower(*p);
|
||||
if (!StrPoolAddStrLen(hostlist, *s, p - *s))
|
||||
{
|
||||
StrPoolDestroy(hostlist);
|
||||
*hostlist = NULL;
|
||||
return false;
|
||||
}
|
||||
// advance to the next line
|
||||
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
|
||||
for (; p < end && (!*p || *p == '\r' || *p == '\n'); p++)
|
||||
;
|
||||
*s = p;
|
||||
return true;
|
||||
}
|
||||
@@ -31,7 +33,7 @@ bool AppendHostList(strpool **hostlist, char *filename)
|
||||
FILE *F;
|
||||
int r;
|
||||
|
||||
DLOG_CONDUP("Loading hostlist %s\n",filename);
|
||||
DLOG_CONDUP("Loading hostlist %s\n", filename);
|
||||
|
||||
if (!(F = fopen(filename, "rb")))
|
||||
{
|
||||
@@ -41,18 +43,19 @@ bool AppendHostList(strpool **hostlist, char *filename)
|
||||
|
||||
if (is_gzip(F))
|
||||
{
|
||||
r = z_readfile(F,&zbuf,&zsize);
|
||||
r = z_readfile(F, &zbuf, &zsize);
|
||||
fclose(F);
|
||||
if (r==Z_OK)
|
||||
if (r == Z_OK)
|
||||
{
|
||||
DLOG_CONDUP("zlib compression detected. uncompressed size : %zu\n", zsize);
|
||||
|
||||
|
||||
p = zbuf;
|
||||
e = zbuf + zsize;
|
||||
while(p<e)
|
||||
while (p < e)
|
||||
{
|
||||
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
|
||||
if (!addpool(hostlist,&p,e))
|
||||
if (*p == '#' || *p == ';' || *p == '/' || *p == '\n')
|
||||
continue;
|
||||
if (!addpool(hostlist, &p, e))
|
||||
{
|
||||
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
|
||||
free(zbuf);
|
||||
@@ -64,19 +67,20 @@ bool AppendHostList(strpool **hostlist, char *filename)
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG_ERR("zlib decompression failed : result %d\n",r);
|
||||
DLOG_ERR("zlib decompression failed : result %d\n", r);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG_CONDUP("loading plain text list\n");
|
||||
|
||||
|
||||
while (fgets(s, 256, F))
|
||||
{
|
||||
p = s;
|
||||
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\n' ) continue;
|
||||
if (!addpool(hostlist,&p,p+strlen(p)))
|
||||
if (*p == '#' || *p == ';' || *p == '/' || *p == '\n')
|
||||
continue;
|
||||
if (!addpool(hostlist, &p, p + strlen(p)))
|
||||
{
|
||||
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
|
||||
fclose(F);
|
||||
@@ -103,7 +107,8 @@ bool LoadHostLists(strpool **hostlist, struct str_list_head *file_list)
|
||||
|
||||
LIST_FOREACH(file, file_list, next)
|
||||
{
|
||||
if (!AppendHostList(hostlist, file->str)) return false;
|
||||
if (!AppendHostList(hostlist, file->str))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -114,7 +119,6 @@ bool NonEmptyHostlist(strpool **hostlist)
|
||||
return *hostlist ? true : StrPoolAddStrLen(hostlist, "@&()", 4);
|
||||
}
|
||||
|
||||
|
||||
bool SearchHostList(strpool *hostlist, const char *host)
|
||||
{
|
||||
if (hostlist)
|
||||
@@ -125,9 +129,11 @@ bool SearchHostList(strpool *hostlist, const char *host)
|
||||
{
|
||||
bInHostList = StrPoolCheckStr(hostlist, p);
|
||||
VPRINT("Hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative");
|
||||
if (bInHostList) return true;
|
||||
if (bInHostList)
|
||||
return true;
|
||||
p = strchr(p, '.');
|
||||
if (p) p++;
|
||||
if (p)
|
||||
p++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -136,13 +142,15 @@ bool SearchHostList(strpool *hostlist, const char *host)
|
||||
// return : true = apply fooling, false = do not apply
|
||||
static bool HostlistCheck_(strpool *hostlist, strpool *hostlist_exclude, const char *host, bool *excluded)
|
||||
{
|
||||
if (excluded) *excluded = false;
|
||||
if (excluded)
|
||||
*excluded = false;
|
||||
if (hostlist_exclude)
|
||||
{
|
||||
VPRINT("Checking exclude hostlist\n");
|
||||
if (SearchHostList(hostlist_exclude, host))
|
||||
{
|
||||
if (excluded) *excluded = true;
|
||||
if (excluded)
|
||||
*excluded = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -160,7 +168,7 @@ bool HostlistCheck(const char *host, bool *excluded)
|
||||
if (*params.hostlist_auto_filename)
|
||||
{
|
||||
time_t t = file_mod_time(params.hostlist_auto_filename);
|
||||
if (t!=params.hostlist_auto_mod_time)
|
||||
if (t != params.hostlist_auto_mod_time)
|
||||
{
|
||||
DLOG_CONDUP("Autohostlist was modified by another process. Reloading include hostslist.\n");
|
||||
if (!LoadIncludeHostLists())
|
||||
|
@@ -6,42 +6,52 @@
|
||||
// taken from an older apple SDK
|
||||
// some fields are different from BSDs
|
||||
|
||||
#define DIOCNATLOOK _IOWR('D', 23, struct pfioc_natlook)
|
||||
#define DIOCNATLOOK _IOWR('D', 23, struct pfioc_natlook)
|
||||
|
||||
enum { PF_INOUT, PF_IN, PF_OUT, PF_FWD };
|
||||
|
||||
struct pf_addr {
|
||||
union {
|
||||
struct in_addr v4;
|
||||
struct in6_addr v6;
|
||||
u_int8_t addr8[16];
|
||||
u_int16_t addr16[8];
|
||||
u_int32_t addr32[4];
|
||||
} pfa; /* 128-bit address */
|
||||
#define v4 pfa.v4
|
||||
#define v6 pfa.v6
|
||||
#define addr8 pfa.addr8
|
||||
#define addr16 pfa.addr16
|
||||
#define addr32 pfa.addr32
|
||||
enum
|
||||
{
|
||||
PF_INOUT,
|
||||
PF_IN,
|
||||
PF_OUT,
|
||||
PF_FWD
|
||||
};
|
||||
|
||||
union pf_state_xport {
|
||||
u_int16_t port;
|
||||
u_int16_t call_id;
|
||||
u_int32_t spi;
|
||||
struct pf_addr
|
||||
{
|
||||
union
|
||||
{
|
||||
struct in_addr v4;
|
||||
struct in6_addr v6;
|
||||
u_int8_t addr8[16];
|
||||
u_int16_t addr16[8];
|
||||
u_int32_t addr32[4];
|
||||
} pfa; /* 128-bit address */
|
||||
#define v4 pfa.v4
|
||||
#define v6 pfa.v6
|
||||
#define addr8 pfa.addr8
|
||||
#define addr16 pfa.addr16
|
||||
#define addr32 pfa.addr32
|
||||
};
|
||||
|
||||
struct pfioc_natlook {
|
||||
struct pf_addr saddr;
|
||||
struct pf_addr daddr;
|
||||
struct pf_addr rsaddr;
|
||||
struct pf_addr rdaddr;
|
||||
union pf_state_xport sxport;
|
||||
union pf_state_xport dxport;
|
||||
union pf_state_xport rsxport;
|
||||
union pf_state_xport rdxport;
|
||||
sa_family_t af;
|
||||
u_int8_t proto;
|
||||
u_int8_t proto_variant;
|
||||
u_int8_t direction;
|
||||
union pf_state_xport
|
||||
{
|
||||
u_int16_t port;
|
||||
u_int16_t call_id;
|
||||
u_int32_t spi;
|
||||
};
|
||||
|
||||
struct pfioc_natlook
|
||||
{
|
||||
struct pf_addr saddr;
|
||||
struct pf_addr daddr;
|
||||
struct pf_addr rsaddr;
|
||||
struct pf_addr rdaddr;
|
||||
union pf_state_xport sxport;
|
||||
union pf_state_xport dxport;
|
||||
union pf_state_xport rsxport;
|
||||
union pf_state_xport rdxport;
|
||||
sa_family_t af;
|
||||
u_int8_t proto;
|
||||
u_int8_t proto_variant;
|
||||
u_int8_t direction;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -9,33 +9,33 @@ int DLOG_FILE(FILE *F, const char *format, va_list args)
|
||||
}
|
||||
int DLOG_CON(const char *format, int syslog_priority, va_list args)
|
||||
{
|
||||
return DLOG_FILE(syslog_priority==LOG_ERR ? stderr : stdout, format, args);
|
||||
return DLOG_FILE(syslog_priority == LOG_ERR ? stderr : stdout, format, args);
|
||||
}
|
||||
int DLOG_FILENAME(const char *filename, const char *format, va_list args)
|
||||
{
|
||||
int r;
|
||||
FILE *F = fopen(filename,"at");
|
||||
FILE *F = fopen(filename, "at");
|
||||
if (F)
|
||||
{
|
||||
r = DLOG_FILE(F, format, args);
|
||||
fclose(F);
|
||||
}
|
||||
else
|
||||
r=-1;
|
||||
r = -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
static char syslog_buf[1024];
|
||||
static size_t syslog_buf_sz=0;
|
||||
static size_t syslog_buf_sz = 0;
|
||||
static void syslog_buffered(int priority, const char *format, va_list args)
|
||||
{
|
||||
if (vsnprintf(syslog_buf+syslog_buf_sz,sizeof(syslog_buf)-syslog_buf_sz,format,args)>0)
|
||||
if (vsnprintf(syslog_buf + syslog_buf_sz, sizeof(syslog_buf) - syslog_buf_sz, format, args) > 0)
|
||||
{
|
||||
syslog_buf_sz=strlen(syslog_buf);
|
||||
syslog_buf_sz = strlen(syslog_buf);
|
||||
// log when buffer is full or buffer ends with \n
|
||||
if (syslog_buf_sz>=(sizeof(syslog_buf)-1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz-1]=='\n'))
|
||||
if (syslog_buf_sz >= (sizeof(syslog_buf) - 1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz - 1] == '\n'))
|
||||
{
|
||||
syslog(priority,"%s",syslog_buf);
|
||||
syslog(priority, "%s", syslog_buf);
|
||||
syslog_buf_sz = 0;
|
||||
}
|
||||
}
|
||||
@@ -43,31 +43,31 @@ static void syslog_buffered(int priority, const char *format, va_list args)
|
||||
|
||||
static int DLOG_VA(const char *format, int syslog_priority, bool condup, int level, va_list args)
|
||||
{
|
||||
int r=0;
|
||||
int r = 0;
|
||||
va_list args2;
|
||||
|
||||
if (condup && !(params.debug>=level && params.debug_target==LOG_TARGET_CONSOLE))
|
||||
if (condup && !(params.debug >= level && params.debug_target == LOG_TARGET_CONSOLE))
|
||||
{
|
||||
va_copy(args2,args);
|
||||
DLOG_CON(format,syslog_priority,args2);
|
||||
va_copy(args2, args);
|
||||
DLOG_CON(format, syslog_priority, args2);
|
||||
}
|
||||
if (params.debug>=level)
|
||||
if (params.debug >= level)
|
||||
{
|
||||
switch(params.debug_target)
|
||||
switch (params.debug_target)
|
||||
{
|
||||
case LOG_TARGET_CONSOLE:
|
||||
r = DLOG_CON(format,syslog_priority,args);
|
||||
break;
|
||||
case LOG_TARGET_FILE:
|
||||
r = DLOG_FILENAME(params.debug_logfile,format,args);
|
||||
break;
|
||||
case LOG_TARGET_SYSLOG:
|
||||
// skip newlines
|
||||
syslog_buffered(syslog_priority,format,args);
|
||||
r = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case LOG_TARGET_CONSOLE:
|
||||
r = DLOG_CON(format, syslog_priority, args);
|
||||
break;
|
||||
case LOG_TARGET_FILE:
|
||||
r = DLOG_FILENAME(params.debug_logfile, format, args);
|
||||
break;
|
||||
case LOG_TARGET_SYSLOG:
|
||||
// skip newlines
|
||||
syslog_buffered(syslog_priority, format, args);
|
||||
r = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
@@ -105,11 +105,10 @@ int DLOG_PERROR(const char *s)
|
||||
return DLOG_ERR("%s: %s\n", s, strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
int LOG_APPEND(const char *filename, const char *format, va_list args)
|
||||
{
|
||||
int r;
|
||||
FILE *F = fopen(filename,"at");
|
||||
FILE *F = fopen(filename, "at");
|
||||
if (F)
|
||||
{
|
||||
fprint_localtime(F);
|
||||
@@ -119,7 +118,7 @@ int LOG_APPEND(const char *filename, const char *format, va_list args)
|
||||
fclose(F);
|
||||
}
|
||||
else
|
||||
r=-1;
|
||||
r = -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@@ -11,21 +11,32 @@
|
||||
#include "helpers.h"
|
||||
#include "protocol.h"
|
||||
|
||||
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
|
||||
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
|
||||
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
|
||||
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
|
||||
|
||||
enum bindll { unwanted=0, no, prefer, force };
|
||||
|
||||
#define MAX_BINDS 32
|
||||
struct bind_s
|
||||
enum bindll
|
||||
{
|
||||
char bindaddr[64],bindiface[IF_NAMESIZE];
|
||||
bool bind_if6;
|
||||
enum bindll bindll;
|
||||
int bind_wait_ifup,bind_wait_ip,bind_wait_ip_ll;
|
||||
unwanted = 0,
|
||||
no,
|
||||
prefer,
|
||||
force
|
||||
};
|
||||
|
||||
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
|
||||
#define MAX_BINDS 32
|
||||
struct bind_s
|
||||
{
|
||||
char bindaddr[64], bindiface[IF_NAMESIZE];
|
||||
bool bind_if6;
|
||||
enum bindll bindll;
|
||||
int bind_wait_ifup, bind_wait_ip, bind_wait_ip_ll;
|
||||
};
|
||||
|
||||
enum log_target
|
||||
{
|
||||
LOG_TARGET_CONSOLE = 0,
|
||||
LOG_TARGET_FILE,
|
||||
LOG_TARGET_SYSLOG
|
||||
};
|
||||
|
||||
struct params_s
|
||||
{
|
||||
@@ -41,10 +52,10 @@ struct params_s
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
bool daemon;
|
||||
int maxconn,resolver_threads,maxfiles,max_orphan_time;
|
||||
int local_rcvbuf,local_sndbuf,remote_rcvbuf,remote_sndbuf;
|
||||
int maxconn, resolver_threads, maxfiles, max_orphan_time;
|
||||
int local_rcvbuf, local_sndbuf, remote_rcvbuf, remote_sndbuf;
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
int tcp_user_timeout_local,tcp_user_timeout_remote;
|
||||
int tcp_user_timeout_local, tcp_user_timeout_remote;
|
||||
#endif
|
||||
|
||||
bool tamper; // any tamper option is set
|
||||
@@ -74,8 +85,8 @@ struct params_s
|
||||
time_t hostlist_auto_mod_time;
|
||||
hostfail_pool *hostlist_auto_fail_counters;
|
||||
|
||||
bool tamper_start_n,tamper_cutoff_n;
|
||||
unsigned int tamper_start,tamper_cutoff;
|
||||
bool tamper_start_n, tamper_cutoff_n;
|
||||
unsigned int tamper_start, tamper_cutoff;
|
||||
|
||||
struct sockaddr_in connect_bind4;
|
||||
struct sockaddr_in6 connect_bind6;
|
||||
|
72
tpws/pools.c
72
tpws/pools.c
@@ -5,33 +5,33 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#define DESTROY_STR_POOL(etype, ppool) \
|
||||
etype *elem, *tmp; \
|
||||
HASH_ITER(hh, *ppool, elem, tmp) { \
|
||||
free(elem->str); \
|
||||
HASH_DEL(*ppool, elem); \
|
||||
free(elem); \
|
||||
}
|
||||
|
||||
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
|
||||
etype *elem; \
|
||||
if (!(elem = (etype*)malloc(sizeof(etype)))) \
|
||||
return false; \
|
||||
if (!(elem->str = malloc(keystr_len + 1))) \
|
||||
{ \
|
||||
free(elem); \
|
||||
return false; \
|
||||
} \
|
||||
memcpy(elem->str, keystr, keystr_len); \
|
||||
elem->str[keystr_len] = 0; \
|
||||
oom = false; \
|
||||
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
|
||||
if (oom) \
|
||||
{ \
|
||||
free(elem->str); \
|
||||
free(elem); \
|
||||
return false; \
|
||||
etype *elem, *tmp; \
|
||||
HASH_ITER(hh, *ppool, elem, tmp) \
|
||||
{ \
|
||||
free(elem->str); \
|
||||
HASH_DEL(*ppool, elem); \
|
||||
free(elem); \
|
||||
}
|
||||
|
||||
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
|
||||
etype *elem; \
|
||||
if (!(elem = (etype *)malloc(sizeof(etype)))) \
|
||||
return false; \
|
||||
if (!(elem->str = malloc(keystr_len + 1))) \
|
||||
{ \
|
||||
free(elem); \
|
||||
return false; \
|
||||
} \
|
||||
memcpy(elem->str, keystr, keystr_len); \
|
||||
elem->str[keystr_len] = 0; \
|
||||
oom = false; \
|
||||
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
|
||||
if (oom) \
|
||||
{ \
|
||||
free(elem->str); \
|
||||
free(elem); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#undef uthash_nonfatal_oom
|
||||
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
|
||||
@@ -65,13 +65,8 @@ void StrPoolDestroy(strpool **pp)
|
||||
DESTROY_STR_POOL(strpool, pp)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HostFailPoolDestroy(hostfail_pool **pp)
|
||||
{
|
||||
DESTROY_STR_POOL(hostfail_pool, pp)
|
||||
}
|
||||
hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time)
|
||||
void HostFailPoolDestroy(hostfail_pool **pp){
|
||||
DESTROY_STR_POOL(hostfail_pool, pp)} hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time)
|
||||
{
|
||||
size_t slen = strlen(s);
|
||||
ADD_STR_POOL(hostfail_pool, pp, s, slen)
|
||||
@@ -79,7 +74,7 @@ hostfail_pool * HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time)
|
||||
elem->counter = 0;
|
||||
return elem;
|
||||
}
|
||||
hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s)
|
||||
hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s)
|
||||
{
|
||||
hostfail_pool *elem;
|
||||
HASH_FIND_STR(p, s, elem);
|
||||
@@ -104,7 +99,7 @@ void HostFailPoolPurge(hostfail_pool **pp)
|
||||
}
|
||||
}
|
||||
}
|
||||
static time_t host_fail_purge_prev=0;
|
||||
static time_t host_fail_purge_prev = 0;
|
||||
void HostFailPoolPurgeRateLimited(hostfail_pool **pp)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
@@ -120,14 +115,14 @@ void HostFailPoolDump(hostfail_pool *p)
|
||||
hostfail_pool *elem, *tmp;
|
||||
time_t now = time(NULL);
|
||||
HASH_ITER(hh, p, elem, tmp)
|
||||
printf("host=%s counter=%d time_left=%lld\n",elem->str,elem->counter,(long long int)elem->expire-now);
|
||||
printf("host=%s counter=%d time_left=%lld\n", elem->str, elem->counter, (long long int)elem->expire - now);
|
||||
}
|
||||
|
||||
|
||||
bool strlist_add(struct str_list_head *head, const char *filename)
|
||||
{
|
||||
struct str_list *entry = malloc(sizeof(struct str_list));
|
||||
if (!entry) return false;
|
||||
if (!entry)
|
||||
return false;
|
||||
entry->str = strdup(filename);
|
||||
if (!entry->str)
|
||||
{
|
||||
@@ -139,7 +134,8 @@ bool strlist_add(struct str_list_head *head, const char *filename)
|
||||
}
|
||||
static void strlist_entry_destroy(struct str_list *entry)
|
||||
{
|
||||
if (entry->str) free(entry->str);
|
||||
if (entry->str)
|
||||
free(entry->str);
|
||||
free(entry);
|
||||
}
|
||||
void strlist_destroy(struct str_list_head *head)
|
||||
|
39
tpws/pools.h
39
tpws/pools.h
@@ -5,38 +5,41 @@
|
||||
#include <sys/queue.h>
|
||||
#include <time.h>
|
||||
|
||||
//#define HASH_BLOOM 20
|
||||
// #define HASH_BLOOM 20
|
||||
#define HASH_NONFATAL_OOM 1
|
||||
#define HASH_FUNCTION HASH_BER
|
||||
#include "uthash.h"
|
||||
|
||||
typedef struct strpool {
|
||||
char *str; /* key */
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
typedef struct strpool
|
||||
{
|
||||
char *str; /* key */
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} strpool;
|
||||
|
||||
void StrPoolDestroy(strpool **pp);
|
||||
bool StrPoolAddStr(strpool **pp,const char *s);
|
||||
bool StrPoolAddStrLen(strpool **pp,const char *s,size_t slen);
|
||||
bool StrPoolCheckStr(strpool *p,const char *s);
|
||||
bool StrPoolAddStr(strpool **pp, const char *s);
|
||||
bool StrPoolAddStrLen(strpool **pp, const char *s, size_t slen);
|
||||
bool StrPoolCheckStr(strpool *p, const char *s);
|
||||
|
||||
struct str_list {
|
||||
char *str;
|
||||
LIST_ENTRY(str_list) next;
|
||||
struct str_list
|
||||
{
|
||||
char *str;
|
||||
LIST_ENTRY(str_list)
|
||||
next;
|
||||
};
|
||||
LIST_HEAD(str_list_head, str_list);
|
||||
|
||||
|
||||
typedef struct hostfail_pool {
|
||||
char *str; /* key */
|
||||
int counter; /* value */
|
||||
time_t expire; /* when to expire record (unixtime) */
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
typedef struct hostfail_pool
|
||||
{
|
||||
char *str; /* key */
|
||||
int counter; /* value */
|
||||
time_t expire; /* when to expire record (unixtime) */
|
||||
UT_hash_handle hh; /* makes this structure hashable */
|
||||
} hostfail_pool;
|
||||
|
||||
void HostFailPoolDestroy(hostfail_pool **pp);
|
||||
hostfail_pool *HostFailPoolAdd(hostfail_pool **pp,const char *s,int fail_time);
|
||||
hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s);
|
||||
hostfail_pool *HostFailPoolAdd(hostfail_pool **pp, const char *s, int fail_time);
|
||||
hostfail_pool *HostFailPoolFind(hostfail_pool *p, const char *s);
|
||||
void HostFailPoolDel(hostfail_pool **pp, hostfail_pool *elem);
|
||||
void HostFailPoolPurge(hostfail_pool **pp);
|
||||
void HostFailPoolPurgeRateLimited(hostfail_pool **pp);
|
||||
|
242
tpws/protocol.c
242
tpws/protocol.c
@@ -7,8 +7,7 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL };
|
||||
const char *http_methods[] = {"GET /", "POST /", "HEAD /", "OPTIONS /", "PUT /", "DELETE /", "CONNECT /", "TRACE /", NULL};
|
||||
const char *HttpMethod(const uint8_t *data, size_t len)
|
||||
{
|
||||
const char **method;
|
||||
@@ -23,56 +22,63 @@ const char *HttpMethod(const uint8_t *data, size_t len)
|
||||
}
|
||||
bool IsHttp(const uint8_t *data, size_t len)
|
||||
{
|
||||
return !!HttpMethod(data,len);
|
||||
return !!HttpMethod(data, len);
|
||||
}
|
||||
// pHost points to "Host: ..."
|
||||
bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs)
|
||||
bool HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs)
|
||||
{
|
||||
if (!*pHost)
|
||||
{
|
||||
*pHost = memmem(buf, bs, "\nHost:", 6);
|
||||
if (*pHost) (*pHost)++;
|
||||
if (*pHost)
|
||||
(*pHost)++;
|
||||
}
|
||||
return !!*pHost;
|
||||
}
|
||||
bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs)
|
||||
bool HttpFindHostConst(const uint8_t **pHost, const uint8_t *buf, size_t bs)
|
||||
{
|
||||
if (!*pHost)
|
||||
{
|
||||
*pHost = memmem(buf, bs, "\nHost:", 6);
|
||||
if (*pHost) (*pHost)++;
|
||||
if (*pHost)
|
||||
(*pHost)++;
|
||||
}
|
||||
return !!*pHost;
|
||||
}
|
||||
bool IsHttpReply(const uint8_t *data, size_t len)
|
||||
{
|
||||
// HTTP/1.x 200\r\n
|
||||
return len>14 && !memcmp(data,"HTTP/1.",7) && (data[7]=='0' || data[7]=='1') && data[8]==' ' &&
|
||||
data[9]>='0' && data[9]<='9' &&
|
||||
data[10]>='0' && data[10]<='9' &&
|
||||
data[11]>='0' && data[11]<='9';
|
||||
return len > 14 && !memcmp(data, "HTTP/1.", 7) && (data[7] == '0' || data[7] == '1') && data[8] == ' ' &&
|
||||
data[9] >= '0' && data[9] <= '9' &&
|
||||
data[10] >= '0' && data[10] <= '9' &&
|
||||
data[11] >= '0' && data[11] <= '9';
|
||||
}
|
||||
int HttpReplyCode(const uint8_t *data, size_t len)
|
||||
{
|
||||
return (data[9]-'0')*100 + (data[10]-'0')*10 + (data[11]-'0');
|
||||
return (data[9] - '0') * 100 + (data[10] - '0') * 10 + (data[11] - '0');
|
||||
}
|
||||
bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char *buf, size_t len_buf)
|
||||
{
|
||||
const uint8_t *p, *s, *e = data + len;
|
||||
|
||||
p = (uint8_t*)strncasestr((char*)data, header, len);
|
||||
if (!p) return false;
|
||||
p = (uint8_t *)strncasestr((char *)data, header, len);
|
||||
if (!p)
|
||||
return false;
|
||||
p += strlen(header);
|
||||
while (p < e && (*p == ' ' || *p == '\t')) p++;
|
||||
while (p < e && (*p == ' ' || *p == '\t'))
|
||||
p++;
|
||||
s = p;
|
||||
while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t')) s++;
|
||||
while (s < e && (*s != '\r' && *s != '\n' && *s != ' ' && *s != '\t'))
|
||||
s++;
|
||||
if (s > p)
|
||||
{
|
||||
size_t slen = s - p;
|
||||
if (buf && len_buf)
|
||||
{
|
||||
if (slen >= len_buf) slen = len_buf - 1;
|
||||
for (size_t i = 0; i < slen; i++) buf[i] = tolower(p[i]);
|
||||
if (slen >= len_buf)
|
||||
slen = len_buf - 1;
|
||||
for (size_t i = 0; i < slen; i++)
|
||||
buf[i] = tolower(p[i]);
|
||||
buf[slen] = 0;
|
||||
}
|
||||
return true;
|
||||
@@ -85,85 +91,98 @@ bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_hos
|
||||
}
|
||||
const char *HttpFind2ndLevelDomain(const char *host)
|
||||
{
|
||||
const char *p=NULL;
|
||||
const char *p = NULL;
|
||||
if (*host)
|
||||
{
|
||||
for (p = host + strlen(host)-1; p>host && *p!='.'; p--);
|
||||
if (*p=='.') for (p--; p>host && *p!='.'; p--);
|
||||
if (*p=='.') p++;
|
||||
for (p = host + strlen(host) - 1; p > host && *p != '.'; p--)
|
||||
;
|
||||
if (*p == '.')
|
||||
for (p--; p > host && *p != '.'; p--)
|
||||
;
|
||||
if (*p == '.')
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
// DPI redirects are global redirects to another domain
|
||||
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host)
|
||||
{
|
||||
char loc[256],*redirect_host, *p;
|
||||
char loc[256], *redirect_host, *p;
|
||||
int code;
|
||||
|
||||
if (!host || !*host) return false;
|
||||
|
||||
code = HttpReplyCode(data,len);
|
||||
|
||||
if ((code!=302 && code!=307) || !HttpExtractHeader(data,len,"\nLocation:",loc,sizeof(loc))) return false;
|
||||
|
||||
if (!host || !*host)
|
||||
return false;
|
||||
|
||||
code = HttpReplyCode(data, len);
|
||||
|
||||
if ((code != 302 && code != 307) || !HttpExtractHeader(data, len, "\nLocation:", loc, sizeof(loc)))
|
||||
return false;
|
||||
|
||||
// something like : https://censor.net/badpage.php?reason=denied&source=RKN
|
||||
|
||||
if (!strncmp(loc,"http://",7))
|
||||
redirect_host=loc+7;
|
||||
else if (!strncmp(loc,"https://",8))
|
||||
redirect_host=loc+8;
|
||||
|
||||
if (!strncmp(loc, "http://", 7))
|
||||
redirect_host = loc + 7;
|
||||
else if (!strncmp(loc, "https://", 8))
|
||||
redirect_host = loc + 8;
|
||||
else
|
||||
return false;
|
||||
|
||||
|
||||
// somethinkg like : censor.net/badpage.php?reason=denied&source=RKN
|
||||
|
||||
for(p=redirect_host; *p && *p!='/' ; p++);
|
||||
*p=0;
|
||||
if (!*redirect_host) return false;
|
||||
|
||||
for (p = redirect_host; *p && *p != '/'; p++)
|
||||
;
|
||||
*p = 0;
|
||||
if (!*redirect_host)
|
||||
return false;
|
||||
|
||||
// somethinkg like : censor.net
|
||||
|
||||
|
||||
// extract 2nd level domains
|
||||
|
||||
const char *dhost = HttpFind2ndLevelDomain(host);
|
||||
const char *drhost = HttpFind2ndLevelDomain(redirect_host);
|
||||
|
||||
return strcasecmp(dhost, drhost)!=0;
|
||||
|
||||
return strcasecmp(dhost, drhost) != 0;
|
||||
}
|
||||
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
|
||||
{
|
||||
const uint8_t *method, *host;
|
||||
int i;
|
||||
|
||||
switch(tpos_type)
|
||||
|
||||
switch (tpos_type)
|
||||
{
|
||||
case httpreqpos_method:
|
||||
// recognize some tpws pre-applied hacks
|
||||
method=http;
|
||||
if (sz<10) break;
|
||||
if (*method=='\n' || *method=='\r') method++;
|
||||
if (*method=='\n' || *method=='\r') method++;
|
||||
for (i=0;i<7;i++) if (*method>='A' && *method<='Z') method++;
|
||||
if (i<3 || *method!=' ') break;
|
||||
return method-http-1;
|
||||
case httpreqpos_host:
|
||||
if (HttpFindHostConst(&host,http,sz) && (host-http+7)<sz)
|
||||
{
|
||||
host+=5;
|
||||
if (*host==' ') host++;
|
||||
return host-http;
|
||||
}
|
||||
case httpreqpos_method:
|
||||
// recognize some tpws pre-applied hacks
|
||||
method = http;
|
||||
if (sz < 10)
|
||||
break;
|
||||
case httpreqpos_pos:
|
||||
if (*method == '\n' || *method == '\r')
|
||||
method++;
|
||||
if (*method == '\n' || *method == '\r')
|
||||
method++;
|
||||
for (i = 0; i < 7; i++)
|
||||
if (*method >= 'A' && *method <= 'Z')
|
||||
method++;
|
||||
if (i < 3 || *method != ' ')
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
return method - http - 1;
|
||||
case httpreqpos_host:
|
||||
if (HttpFindHostConst(&host, http, sz) && (host - http + 7) < sz)
|
||||
{
|
||||
host += 5;
|
||||
if (*host == ' ')
|
||||
host++;
|
||||
return host - http;
|
||||
}
|
||||
break;
|
||||
case httpreqpos_pos:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return hpos_pos<sz ? hpos_pos : 0;
|
||||
return hpos_pos < sz ? hpos_pos : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint16_t TLSRecordDataLen(const uint8_t *data)
|
||||
{
|
||||
return pntoh16(data + 3);
|
||||
@@ -174,7 +193,7 @@ size_t TLSRecordLen(const uint8_t *data)
|
||||
}
|
||||
bool IsTLSRecordFull(const uint8_t *data, size_t len)
|
||||
{
|
||||
return TLSRecordLen(data)<=len;
|
||||
return TLSRecordLen(data) <= len;
|
||||
}
|
||||
bool IsTLSClientHello(const uint8_t *data, size_t len, bool bPartialIsOK)
|
||||
{
|
||||
@@ -201,41 +220,52 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
|
||||
|
||||
l = 1 + 3 + 2 + 32;
|
||||
// SessionIDLength
|
||||
if (len < (l + 1)) return false;
|
||||
if (len < (l + 1))
|
||||
return false;
|
||||
if (!bPartialIsOK)
|
||||
{
|
||||
ll = data[1] << 16 | data[2] << 8 | data[3]; // HandshakeProtocol length
|
||||
if (len < (ll + 4)) return false;
|
||||
ll = data[1] << 16 | data[2] << 8 | data[3]; // HandshakeProtocol length
|
||||
if (len < (ll + 4))
|
||||
return false;
|
||||
}
|
||||
l += data[l] + 1;
|
||||
// CipherSuitesLength
|
||||
if (len < (l + 2)) return false;
|
||||
if (len < (l + 2))
|
||||
return false;
|
||||
l += pntoh16(data + l) + 2;
|
||||
// CompressionMethodsLength
|
||||
if (len < (l + 1)) return false;
|
||||
if (len < (l + 1))
|
||||
return false;
|
||||
l += data[l] + 1;
|
||||
// ExtensionsLength
|
||||
if (len < (l + 2)) return false;
|
||||
if (len < (l + 2))
|
||||
return false;
|
||||
|
||||
data += l; len -= l;
|
||||
data += l;
|
||||
len -= l;
|
||||
l = pntoh16(data);
|
||||
data += 2; len -= 2;
|
||||
|
||||
data += 2;
|
||||
len -= 2;
|
||||
|
||||
if (bPartialIsOK)
|
||||
{
|
||||
if (len < l) l = len;
|
||||
if (len < l)
|
||||
l = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len < l) return false;
|
||||
if (len < l)
|
||||
return false;
|
||||
}
|
||||
|
||||
while (l >= 4)
|
||||
{
|
||||
uint16_t etype = pntoh16(data);
|
||||
size_t elen = pntoh16(data + 2);
|
||||
data += 4; l -= 4;
|
||||
if (l < elen) break;
|
||||
data += 4;
|
||||
l -= 4;
|
||||
if (l < elen)
|
||||
break;
|
||||
if (etype == type)
|
||||
{
|
||||
if (ext && len_ext)
|
||||
@@ -245,7 +275,8 @@ bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const
|
||||
}
|
||||
return true;
|
||||
}
|
||||
data += elen; l -= elen;
|
||||
data += elen;
|
||||
l -= elen;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -257,9 +288,11 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
|
||||
// u16 Version: TLS1.0
|
||||
// u16 Length
|
||||
size_t reclen;
|
||||
if (!IsTLSClientHello(data, len, bPartialIsOK)) return false;
|
||||
reclen=TLSRecordLen(data);
|
||||
if (reclen<len) len=reclen; // correct len if it has more data than the first tls record has
|
||||
if (!IsTLSClientHello(data, len, bPartialIsOK))
|
||||
return false;
|
||||
reclen = TLSRecordLen(data);
|
||||
if (reclen < len)
|
||||
len = reclen; // correct len if it has more data than the first tls record has
|
||||
return TLSFindExtInHandshake(data + 5, len - 5, type, ext, len_ext, bPartialIsOK);
|
||||
}
|
||||
static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, size_t len_host)
|
||||
@@ -267,14 +300,19 @@ static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, s
|
||||
// u16 data+0 - name list length
|
||||
// u8 data+2 - server name type. 0=host_name
|
||||
// u16 data+3 - server name length
|
||||
if (elen < 5 || ext[2] != 0) return false;
|
||||
if (elen < 5 || ext[2] != 0)
|
||||
return false;
|
||||
size_t slen = pntoh16(ext + 3);
|
||||
ext += 5; elen -= 5;
|
||||
if (slen < elen) return false;
|
||||
ext += 5;
|
||||
elen -= 5;
|
||||
if (slen < elen)
|
||||
return false;
|
||||
if (host && len_host)
|
||||
{
|
||||
if (slen >= len_host) slen = len_host - 1;
|
||||
for (size_t i = 0; i < slen; i++) host[i] = tolower(ext[i]);
|
||||
if (slen >= len_host)
|
||||
slen = len_host - 1;
|
||||
for (size_t i = 0; i < slen; i++)
|
||||
host[i] = tolower(ext[i]);
|
||||
host[slen] = 0;
|
||||
}
|
||||
return true;
|
||||
@@ -284,7 +322,8 @@ bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len
|
||||
const uint8_t *ext;
|
||||
size_t elen;
|
||||
|
||||
if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK)) return false;
|
||||
if (!TLSFindExt(data, len, 0, &ext, &elen, bPartialIsOK))
|
||||
return false;
|
||||
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
||||
}
|
||||
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK)
|
||||
@@ -292,23 +331,24 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
|
||||
const uint8_t *ext;
|
||||
size_t elen;
|
||||
|
||||
if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK)) return false;
|
||||
if (!TLSFindExtInHandshake(data, len, 0, &ext, &elen, bPartialIsOK))
|
||||
return false;
|
||||
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
||||
}
|
||||
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
|
||||
{
|
||||
size_t elen;
|
||||
const uint8_t *ext;
|
||||
switch(tpos_type)
|
||||
switch (tpos_type)
|
||||
{
|
||||
case tlspos_sni:
|
||||
case tlspos_sniext:
|
||||
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
|
||||
return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1;
|
||||
// fall through
|
||||
case tlspos_pos:
|
||||
return tpos_pos<sz ? tpos_pos : 0;
|
||||
default:
|
||||
return 0;
|
||||
case tlspos_sni:
|
||||
case tlspos_sniext:
|
||||
if (TLSFindExt(tls, sz, 0, &ext, &elen, false))
|
||||
return (tpos_type == tlspos_sni) ? ext - tls + 6 : ext - tls + 1;
|
||||
// fall through
|
||||
case tlspos_pos:
|
||||
return tpos_pos < sz ? tpos_pos : 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@@ -7,8 +7,8 @@
|
||||
extern const char *http_methods[9];
|
||||
const char *HttpMethod(const uint8_t *data, size_t len);
|
||||
bool IsHttp(const uint8_t *data, size_t len);
|
||||
bool HttpFindHost(uint8_t **pHost,uint8_t *buf,size_t bs);
|
||||
bool HttpFindHostConst(const uint8_t **pHost,const uint8_t *buf,size_t bs);
|
||||
bool HttpFindHost(uint8_t **pHost, uint8_t *buf, size_t bs);
|
||||
bool HttpFindHostConst(const uint8_t **pHost, const uint8_t *buf, size_t bs);
|
||||
// header must be passed like this : "\nHost:"
|
||||
bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char *buf, size_t len_buf);
|
||||
bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host);
|
||||
@@ -18,7 +18,13 @@ const char *HttpFind2ndLevelDomain(const char *host);
|
||||
int HttpReplyCode(const uint8_t *data, size_t len);
|
||||
// must be pre-checked by IsHttpReply
|
||||
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
||||
enum httpreqpos { httpreqpos_none = 0, httpreqpos_method, httpreqpos_host, httpreqpos_pos };
|
||||
enum httpreqpos
|
||||
{
|
||||
httpreqpos_none = 0,
|
||||
httpreqpos_method,
|
||||
httpreqpos_host,
|
||||
httpreqpos_pos
|
||||
};
|
||||
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz);
|
||||
|
||||
uint16_t TLSRecordDataLen(const uint8_t *data);
|
||||
@@ -29,5 +35,11 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
|
||||
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
||||
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
||||
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
||||
enum tlspos { tlspos_none = 0, tlspos_sni, tlspos_sniext, tlspos_pos };
|
||||
enum tlspos
|
||||
{
|
||||
tlspos_none = 0,
|
||||
tlspos_sni,
|
||||
tlspos_sniext,
|
||||
tlspos_pos
|
||||
};
|
||||
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);
|
||||
|
139
tpws/redirect.c
139
tpws/redirect.c
@@ -11,23 +11,22 @@
|
||||
#include "helpers.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#ifndef IP6T_SO_ORIGINAL_DST
|
||||
#define IP6T_SO_ORIGINAL_DST 80
|
||||
#endif
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#ifndef IP6T_SO_ORIGINAL_DST
|
||||
#define IP6T_SO_ORIGINAL_DST 80
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(BSD)
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/pfvar.h>
|
||||
|
||||
static int redirector_fd=-1;
|
||||
static int redirector_fd = -1;
|
||||
|
||||
void redir_close(void)
|
||||
{
|
||||
if (redirector_fd!=-1)
|
||||
if (redirector_fd != -1)
|
||||
{
|
||||
close(redirector_fd);
|
||||
redirector_fd = -1;
|
||||
@@ -43,7 +42,7 @@ static bool redir_open_private(const char *fname, int flags)
|
||||
DLOG_PERROR("redir_openv_private");
|
||||
return false;
|
||||
}
|
||||
DBGPRINT("opened redirector %s\n",fname);
|
||||
DBGPRINT("opened redirector %s\n", fname);
|
||||
return true;
|
||||
}
|
||||
bool redir_init(void)
|
||||
@@ -56,74 +55,79 @@ static bool destination_from_pf(const struct sockaddr *accept_sa, struct sockadd
|
||||
struct pfioc_natlook nl;
|
||||
struct sockaddr_storage asa2;
|
||||
|
||||
if (redirector_fd==-1) return false;
|
||||
if (redirector_fd == -1)
|
||||
return false;
|
||||
|
||||
if (params.debug>=2)
|
||||
if (params.debug >= 2)
|
||||
{
|
||||
char s[48],s2[48];
|
||||
*s=0; ntop46_port(accept_sa, s, sizeof(s));
|
||||
*s2=0; ntop46_port((struct sockaddr *)orig_dst, s2, sizeof(s2));
|
||||
DBGPRINT("destination_from_pf %s %s\n",s,s2);
|
||||
char s[48], s2[48];
|
||||
*s = 0;
|
||||
ntop46_port(accept_sa, s, sizeof(s));
|
||||
*s2 = 0;
|
||||
ntop46_port((struct sockaddr *)orig_dst, s2, sizeof(s2));
|
||||
DBGPRINT("destination_from_pf %s %s\n", s, s2);
|
||||
}
|
||||
|
||||
saconvmapped(orig_dst);
|
||||
if (accept_sa->sa_family==AF_INET6 && orig_dst->ss_family==AF_INET)
|
||||
if (accept_sa->sa_family == AF_INET6 && orig_dst->ss_family == AF_INET)
|
||||
{
|
||||
memcpy(&asa2,accept_sa,sizeof(struct sockaddr_in6));
|
||||
memcpy(&asa2, accept_sa, sizeof(struct sockaddr_in6));
|
||||
saconvmapped(&asa2);
|
||||
accept_sa = (struct sockaddr*)&asa2;
|
||||
accept_sa = (struct sockaddr *)&asa2;
|
||||
}
|
||||
|
||||
if (params.debug>=2)
|
||||
if (params.debug >= 2)
|
||||
{
|
||||
char s[48],s2[48];
|
||||
*s=0; ntop46_port(accept_sa, s, sizeof(s));
|
||||
*s2=0; ntop46_port((struct sockaddr *)orig_dst, s2, sizeof(s2));
|
||||
DBGPRINT("destination_from_pf (saconvmapped) %s %s\n",s,s2);
|
||||
char s[48], s2[48];
|
||||
*s = 0;
|
||||
ntop46_port(accept_sa, s, sizeof(s));
|
||||
*s2 = 0;
|
||||
ntop46_port((struct sockaddr *)orig_dst, s2, sizeof(s2));
|
||||
DBGPRINT("destination_from_pf (saconvmapped) %s %s\n", s, s2);
|
||||
}
|
||||
|
||||
if (accept_sa->sa_family!=orig_dst->ss_family)
|
||||
if (accept_sa->sa_family != orig_dst->ss_family)
|
||||
{
|
||||
DBGPRINT("accept_sa and orig_dst sa_family mismatch : %d %d\n", accept_sa->sa_family, orig_dst->ss_family);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&nl, 0, sizeof(nl));
|
||||
nl.proto = IPPROTO_TCP;
|
||||
nl.direction = PF_OUT;
|
||||
nl.proto = IPPROTO_TCP;
|
||||
nl.direction = PF_OUT;
|
||||
nl.af = orig_dst->ss_family;
|
||||
switch(orig_dst->ss_family)
|
||||
switch (orig_dst->ss_family)
|
||||
{
|
||||
case AF_INET:
|
||||
{
|
||||
{
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)orig_dst;
|
||||
nl.daddr.v4.s_addr = sin->sin_addr.s_addr;
|
||||
nl.saddr.v4.s_addr = ((struct sockaddr_in*)accept_sa)->sin_addr.s_addr;
|
||||
nl.saddr.v4.s_addr = ((struct sockaddr_in *)accept_sa)->sin_addr.s_addr;
|
||||
#ifdef __APPLE__
|
||||
nl.sxport.port = ((struct sockaddr_in*)accept_sa)->sin_port;
|
||||
nl.dxport.port = sin->sin_port;
|
||||
nl.sxport.port = ((struct sockaddr_in *)accept_sa)->sin_port;
|
||||
nl.dxport.port = sin->sin_port;
|
||||
#else
|
||||
nl.sport = ((struct sockaddr_in*)accept_sa)->sin_port;
|
||||
nl.dport = sin->sin_port;
|
||||
nl.sport = ((struct sockaddr_in *)accept_sa)->sin_port;
|
||||
nl.dport = sin->sin_port;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
{
|
||||
{
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)orig_dst;
|
||||
nl.daddr.v6 = sin6->sin6_addr;
|
||||
nl.saddr.v6 = ((struct sockaddr_in6*)accept_sa)->sin6_addr;
|
||||
nl.saddr.v6 = ((struct sockaddr_in6 *)accept_sa)->sin6_addr;
|
||||
#ifdef __APPLE__
|
||||
nl.sxport.port = ((struct sockaddr_in6*)accept_sa)->sin6_port;
|
||||
nl.sxport.port = ((struct sockaddr_in6 *)accept_sa)->sin6_port;
|
||||
nl.dxport.port = sin6->sin6_port;
|
||||
#else
|
||||
nl.sport = ((struct sockaddr_in6*)accept_sa)->sin6_port;
|
||||
nl.sport = ((struct sockaddr_in6 *)accept_sa)->sin6_port;
|
||||
nl.dport = sin6->sin6_port;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DBGPRINT("destination_from_pf : unexpected address family %d\n",orig_dst->ss_family);
|
||||
DBGPRINT("destination_from_pf : unexpected address family %d\n", orig_dst->ss_family);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -134,45 +138,42 @@ static bool destination_from_pf(const struct sockaddr *accept_sa, struct sockadd
|
||||
}
|
||||
DBGPRINT("destination_from_pf : got orig dest addr from pf\n");
|
||||
|
||||
switch(nl.af)
|
||||
switch (nl.af)
|
||||
{
|
||||
case AF_INET:
|
||||
orig_dst->ss_family = nl.af;
|
||||
#ifdef __APPLE__
|
||||
((struct sockaddr_in*)orig_dst)->sin_port = nl.rdxport.port;
|
||||
((struct sockaddr_in *)orig_dst)->sin_port = nl.rdxport.port;
|
||||
#else
|
||||
((struct sockaddr_in*)orig_dst)->sin_port = nl.rdport;
|
||||
((struct sockaddr_in *)orig_dst)->sin_port = nl.rdport;
|
||||
#endif
|
||||
((struct sockaddr_in*)orig_dst)->sin_addr = nl.rdaddr.v4;
|
||||
((struct sockaddr_in *)orig_dst)->sin_addr = nl.rdaddr.v4;
|
||||
break;
|
||||
case AF_INET6:
|
||||
orig_dst->ss_family = nl.af;
|
||||
#ifdef __APPLE__
|
||||
((struct sockaddr_in6*)orig_dst)->sin6_port = nl.rdxport.port;
|
||||
((struct sockaddr_in6 *)orig_dst)->sin6_port = nl.rdxport.port;
|
||||
#else
|
||||
((struct sockaddr_in6*)orig_dst)->sin6_port = nl.rdport;
|
||||
((struct sockaddr_in6 *)orig_dst)->sin6_port = nl.rdport;
|
||||
#endif
|
||||
((struct sockaddr_in6*)orig_dst)->sin6_addr = nl.rdaddr.v6;
|
||||
((struct sockaddr_in6 *)orig_dst)->sin6_addr = nl.rdaddr.v6;
|
||||
break;
|
||||
default:
|
||||
DBGPRINT("destination_from_pf : DIOCNATLOOK returned unexpected address family %d\n",nl.af);
|
||||
DBGPRINT("destination_from_pf : DIOCNATLOOK returned unexpected address family %d\n", nl.af);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
bool redir_init(void) {return true;}
|
||||
bool redir_init(void) { return true; }
|
||||
void redir_close(void) {};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//Store the original destination address in orig_dst
|
||||
// Store the original destination address in orig_dst
|
||||
bool get_dest_addr(int sockfd, const struct sockaddr *accept_sa, struct sockaddr_storage *orig_dst)
|
||||
{
|
||||
char orig_dst_str[INET6_ADDRSTRLEN];
|
||||
@@ -181,28 +182,28 @@ bool get_dest_addr(int sockfd, const struct sockaddr *accept_sa, struct sockaddr
|
||||
|
||||
memset(orig_dst, 0, addrlen);
|
||||
|
||||
//For UDP transparent proxying:
|
||||
//Set IP_RECVORIGDSTADDR socket option for getting the original
|
||||
//destination of a datagram
|
||||
// For UDP transparent proxying:
|
||||
// Set IP_RECVORIGDSTADDR socket option for getting the original
|
||||
// destination of a datagram
|
||||
|
||||
#ifdef __linux__
|
||||
// DNAT
|
||||
r=getsockopt(sockfd, SOL_IP, SO_ORIGINAL_DST, (struct sockaddr*) orig_dst, &addrlen);
|
||||
if (r<0)
|
||||
r = getsockopt(sockfd, SOL_IPV6, IP6T_SO_ORIGINAL_DST, (struct sockaddr*) orig_dst, &addrlen);
|
||||
if (r<0)
|
||||
r = getsockopt(sockfd, SOL_IP, SO_ORIGINAL_DST, (struct sockaddr *)orig_dst, &addrlen);
|
||||
if (r < 0)
|
||||
r = getsockopt(sockfd, SOL_IPV6, IP6T_SO_ORIGINAL_DST, (struct sockaddr *)orig_dst, &addrlen);
|
||||
if (r < 0)
|
||||
{
|
||||
DBGPRINT("both SO_ORIGINAL_DST and IP6T_SO_ORIGINAL_DST failed !\n");
|
||||
#endif
|
||||
// TPROXY : socket is bound to original destination
|
||||
r=getsockname(sockfd, (struct sockaddr*) orig_dst, &addrlen);
|
||||
if (r<0)
|
||||
r = getsockname(sockfd, (struct sockaddr *)orig_dst, &addrlen);
|
||||
if (r < 0)
|
||||
{
|
||||
DLOG_PERROR("getsockname");
|
||||
return false;
|
||||
}
|
||||
if (orig_dst->ss_family==AF_INET6)
|
||||
((struct sockaddr_in6*)orig_dst)->sin6_scope_id=0; // or MacOS will not connect()
|
||||
if (orig_dst->ss_family == AF_INET6)
|
||||
((struct sockaddr_in6 *)orig_dst)->sin6_scope_id = 0; // or macOS will not connect()
|
||||
#ifdef BSD
|
||||
if (params.pf_enable && !destination_from_pf(accept_sa, orig_dst))
|
||||
DBGPRINT("pf filter destination_from_pf failed\n");
|
||||
@@ -217,13 +218,13 @@ bool get_dest_addr(int sockfd, const struct sockaddr *accept_sa, struct sockaddr
|
||||
{
|
||||
if (orig_dst->ss_family == AF_INET)
|
||||
{
|
||||
inet_ntop(AF_INET, &(((struct sockaddr_in*) orig_dst)->sin_addr), orig_dst_str, INET_ADDRSTRLEN);
|
||||
VPRINT("Original destination for socket fd=%d : %s:%d\n", sockfd,orig_dst_str, htons(((struct sockaddr_in*) orig_dst)->sin_port));
|
||||
inet_ntop(AF_INET, &(((struct sockaddr_in *)orig_dst)->sin_addr), orig_dst_str, INET_ADDRSTRLEN);
|
||||
VPRINT("Original destination for socket fd=%d : %s:%d\n", sockfd, orig_dst_str, htons(((struct sockaddr_in *)orig_dst)->sin_port));
|
||||
}
|
||||
else if (orig_dst->ss_family == AF_INET6)
|
||||
{
|
||||
inet_ntop(AF_INET6,&(((struct sockaddr_in6*) orig_dst)->sin6_addr), orig_dst_str, INET6_ADDRSTRLEN);
|
||||
VPRINT("Original destination for socket fd=%d : [%s]:%d\n", sockfd,orig_dst_str, htons(((struct sockaddr_in6*) orig_dst)->sin6_port));
|
||||
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)orig_dst)->sin6_addr), orig_dst_str, INET6_ADDRSTRLEN);
|
||||
VPRINT("Original destination for socket fd=%d : [%s]:%d\n", sockfd, orig_dst_str, htons(((struct sockaddr_in6 *)orig_dst)->sin6_port));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
109
tpws/resolver.c
109
tpws/resolver.c
@@ -7,7 +7,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <semaphore.h>
|
||||
#include <fcntl.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <sys/syscall.h>
|
||||
@@ -17,7 +17,7 @@
|
||||
#define SIG_BREAK SIGUSR1
|
||||
|
||||
#ifdef __APPLE__
|
||||
static const char *sem_name="/tpws_resolver";
|
||||
static const char *sem_name = "/tpws_resolver";
|
||||
#endif
|
||||
|
||||
TAILQ_HEAD(resolve_tailhead, resolve_item);
|
||||
@@ -35,7 +35,7 @@ typedef struct
|
||||
pthread_t *thread;
|
||||
bool bInit, bStop;
|
||||
} t_resolver;
|
||||
static t_resolver resolver = { .bInit = false };
|
||||
static t_resolver resolver = {.bInit = false};
|
||||
|
||||
#define rlist_lock pthread_mutex_lock(&resolver.resolve_list_lock)
|
||||
#define rlist_unlock pthread_mutex_unlock(&resolver.resolve_list_lock)
|
||||
@@ -47,7 +47,8 @@ static void resolver_clear_list(void)
|
||||
for (;;)
|
||||
{
|
||||
ri = TAILQ_FIRST(&resolver.resolve_list);
|
||||
if (!ri) break;
|
||||
if (!ri)
|
||||
break;
|
||||
TAILQ_REMOVE(&resolver.resolve_list, ri, next);
|
||||
free(ri);
|
||||
}
|
||||
@@ -57,7 +58,7 @@ int resolver_thread_count(void)
|
||||
{
|
||||
return resolver.bInit ? resolver.threads : 0;
|
||||
}
|
||||
|
||||
|
||||
static void *resolver_thread(void *arg)
|
||||
{
|
||||
int r;
|
||||
@@ -66,15 +67,17 @@ static void *resolver_thread(void *arg)
|
||||
sigemptyset(&signal_mask);
|
||||
sigaddset(&signal_mask, SIG_BREAK);
|
||||
|
||||
//printf("resolver_thread %d start\n",syscall(SYS_gettid));
|
||||
for(;;)
|
||||
// printf("resolver_thread %d start\n",syscall(SYS_gettid));
|
||||
for (;;)
|
||||
{
|
||||
if (resolver.bStop) break;
|
||||
if (resolver.bStop)
|
||||
break;
|
||||
r = sem_wait(resolver.sem);
|
||||
if (resolver.bStop) break;
|
||||
if (resolver.bStop)
|
||||
break;
|
||||
if (r)
|
||||
{
|
||||
if (errno!=EINTR)
|
||||
if (errno != EINTR)
|
||||
{
|
||||
DLOG_PERROR("sem_wait (resolver_thread)");
|
||||
break; // fatal err
|
||||
@@ -87,36 +90,37 @@ static void *resolver_thread(void *arg)
|
||||
|
||||
rlist_lock;
|
||||
ri = TAILQ_FIRST(&resolver.resolve_list);
|
||||
if (ri) TAILQ_REMOVE(&resolver.resolve_list, ri, next);
|
||||
if (ri)
|
||||
TAILQ_REMOVE(&resolver.resolve_list, ri, next);
|
||||
rlist_unlock;
|
||||
|
||||
if (ri)
|
||||
{
|
||||
struct addrinfo *ai,hints;
|
||||
struct addrinfo *ai, hints;
|
||||
char sport[6];
|
||||
|
||||
//printf("THREAD %d GOT JOB %s\n", syscall(SYS_gettid), ri->dom);
|
||||
snprintf(sport,sizeof(sport),"%u",ri->port);
|
||||
// printf("THREAD %d GOT JOB %s\n", syscall(SYS_gettid), ri->dom);
|
||||
snprintf(sport, sizeof(sport), "%u", ri->port);
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
// unfortunately getaddrinfo cannot be interrupted with a signal. we cannot cancel a query
|
||||
ri->ga_res = getaddrinfo(ri->dom,sport,&hints,&ai);
|
||||
ri->ga_res = getaddrinfo(ri->dom, sport, &hints, &ai);
|
||||
if (!ri->ga_res)
|
||||
{
|
||||
memcpy(&ri->ss, ai->ai_addr, ai->ai_addrlen);
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
//printf("THREAD %d END JOB %s FIRST=%p\n", syscall(SYS_gettid), ri->dom, TAILQ_FIRST(&resolver.resolve_list));
|
||||
// printf("THREAD %d END JOB %s FIRST=%p\n", syscall(SYS_gettid), ri->dom, TAILQ_FIRST(&resolver.resolve_list));
|
||||
|
||||
// never interrupt this
|
||||
pthread_sigmask(SIG_BLOCK, &signal_mask, NULL);
|
||||
wr = write(resolver.fd_signal_pipe,&ri,sizeof(void*));
|
||||
if (wr<0)
|
||||
wr = write(resolver.fd_signal_pipe, &ri, sizeof(void *));
|
||||
if (wr < 0)
|
||||
{
|
||||
free(ri);
|
||||
DLOG_PERROR("write resolve_pipe");
|
||||
}
|
||||
else if (wr!=sizeof(void*))
|
||||
else if (wr != sizeof(void *))
|
||||
{
|
||||
// partial pointer write is FATAL. in any case it will cause pointer corruption and coredump
|
||||
free(ri);
|
||||
@@ -127,7 +131,7 @@ static void *resolver_thread(void *arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
//printf("resolver_thread %d exit\n",syscall(SYS_gettid));
|
||||
// printf("resolver_thread %d exit\n",syscall(SYS_gettid));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -149,19 +153,19 @@ void resolver_deinit(void)
|
||||
pthread_kill(resolver.thread[t], SIGUSR1);
|
||||
pthread_join(resolver.thread[t], NULL);
|
||||
}
|
||||
|
||||
|
||||
pthread_mutex_destroy(&resolver.resolve_list_lock);
|
||||
free(resolver.thread);
|
||||
|
||||
#ifdef __APPLE__
|
||||
sem_close(resolver.sem);
|
||||
#else
|
||||
sem_destroy(resolver.sem);
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
sem_close(resolver.sem);
|
||||
#else
|
||||
sem_destroy(resolver.sem);
|
||||
#endif
|
||||
|
||||
resolver_clear_list();
|
||||
|
||||
memset(&resolver,0,sizeof(resolver));
|
||||
memset(&resolver, 0, sizeof(resolver));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,18 +174,19 @@ bool resolver_init(int threads, int fd_signal_pipe)
|
||||
int t;
|
||||
struct sigaction action;
|
||||
|
||||
if (threads<1 || resolver.bInit) return false;
|
||||
if (threads < 1 || resolver.bInit)
|
||||
return false;
|
||||
|
||||
memset(&resolver,0,sizeof(resolver));
|
||||
memset(&resolver, 0, sizeof(resolver));
|
||||
resolver.bInit = true;
|
||||
|
||||
#ifdef __APPLE__
|
||||
// MacOS does not support unnamed semaphores
|
||||
|
||||
char sn[64];
|
||||
snprintf(sn,sizeof(sn),"%s_%d",sem_name,getpid());
|
||||
resolver.sem = sem_open(sn,O_CREAT,0600,0);
|
||||
if (resolver.sem==SEM_FAILED)
|
||||
snprintf(sn, sizeof(sn), "%s_%d", sem_name, getpid());
|
||||
resolver.sem = sem_open(sn, O_CREAT, 0600, 0);
|
||||
if (resolver.sem == SEM_FAILED)
|
||||
{
|
||||
DLOG_PERROR("sem_open");
|
||||
goto ex;
|
||||
@@ -189,48 +194,51 @@ bool resolver_init(int threads, int fd_signal_pipe)
|
||||
// unlink immediately to remove tails
|
||||
sem_unlink(sn);
|
||||
#else
|
||||
if (sem_init(&resolver._sem,0,0)==-1)
|
||||
{
|
||||
if (sem_init(&resolver._sem, 0, 0) == -1)
|
||||
{
|
||||
DLOG_PERROR("sem_init");
|
||||
goto ex;
|
||||
}
|
||||
resolver.sem = &resolver._sem;
|
||||
#endif
|
||||
|
||||
if (pthread_mutex_init(&resolver.resolve_list_lock, NULL)) goto ex;
|
||||
if (pthread_mutex_init(&resolver.resolve_list_lock, NULL))
|
||||
goto ex;
|
||||
|
||||
resolver.fd_signal_pipe = fd_signal_pipe;
|
||||
TAILQ_INIT(&resolver.resolve_list);
|
||||
|
||||
// start as many threads as we can up to specified number
|
||||
resolver.thread = malloc(sizeof(pthread_t)*threads);
|
||||
if (!resolver.thread) goto ex;
|
||||
resolver.thread = malloc(sizeof(pthread_t) * threads);
|
||||
if (!resolver.thread)
|
||||
goto ex;
|
||||
|
||||
memset(&action,0,sizeof(action));
|
||||
memset(&action, 0, sizeof(action));
|
||||
action.sa_handler = sigbreak;
|
||||
sigaction(SIG_BREAK, &action, NULL);
|
||||
|
||||
|
||||
pthread_attr_t attr;
|
||||
if (pthread_attr_init(&attr)) goto ex;
|
||||
if (pthread_attr_init(&attr))
|
||||
goto ex;
|
||||
// set minimum thread stack size
|
||||
|
||||
if (pthread_attr_setstacksize(&attr,PTHREAD_STACK_MIN>20480 ? PTHREAD_STACK_MIN : 20480))
|
||||
if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN > 20480 ? PTHREAD_STACK_MIN : 20480))
|
||||
{
|
||||
pthread_attr_destroy(&attr);
|
||||
goto ex;
|
||||
}
|
||||
|
||||
for(t=0, resolver.threads=threads ; t<threads ; t++)
|
||||
for (t = 0, resolver.threads = threads; t < threads; t++)
|
||||
{
|
||||
if (pthread_create(resolver.thread + t, &attr, resolver_thread, NULL))
|
||||
{
|
||||
resolver.threads=t;
|
||||
resolver.threads = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_attr_destroy(&attr);
|
||||
if (!resolver.threads) goto ex;
|
||||
if (!resolver.threads)
|
||||
goto ex;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -239,22 +247,21 @@ ex:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct resolve_item *resolver_queue(const char *dom, uint16_t port, void *ptr)
|
||||
{
|
||||
struct resolve_item *ri = calloc(1,sizeof(struct resolve_item));
|
||||
if (!ri) return NULL;
|
||||
struct resolve_item *ri = calloc(1, sizeof(struct resolve_item));
|
||||
if (!ri)
|
||||
return NULL;
|
||||
|
||||
strncpy(ri->dom,dom,sizeof(ri->dom));
|
||||
ri->dom[sizeof(ri->dom)-1] = 0;
|
||||
strncpy(ri->dom, dom, sizeof(ri->dom));
|
||||
ri->dom[sizeof(ri->dom) - 1] = 0;
|
||||
ri->port = port;
|
||||
ri->ptr = ptr;
|
||||
|
||||
rlist_lock;
|
||||
TAILQ_INSERT_TAIL(&resolver.resolve_list, ri, next);
|
||||
rlist_unlock;
|
||||
if (sem_post(resolver.sem)<0)
|
||||
if (sem_post(resolver.sem) < 0)
|
||||
{
|
||||
DLOG_PERROR("resolver_queue sem_post");
|
||||
free(ri);
|
||||
|
@@ -8,12 +8,13 @@
|
||||
|
||||
struct resolve_item
|
||||
{
|
||||
char dom[256]; // request dom
|
||||
char dom[256]; // request dom
|
||||
struct sockaddr_storage ss; // resolve result
|
||||
int ga_res; // getaddrinfo result code
|
||||
uint16_t port; // request port
|
||||
int ga_res; // getaddrinfo result code
|
||||
uint16_t port; // request port
|
||||
void *ptr;
|
||||
TAILQ_ENTRY(resolve_item) next;
|
||||
TAILQ_ENTRY(resolve_item)
|
||||
next;
|
||||
};
|
||||
|
||||
struct resolve_item *resolver_queue(const char *dom, uint16_t port, void *ptr);
|
||||
|
167
tpws/sec.c
167
tpws/sec.c
@@ -23,103 +23,102 @@
|
||||
// block most of the undesired syscalls to harden against code execution
|
||||
static long blocked_syscalls[] = {
|
||||
#ifdef SYS_execv
|
||||
SYS_execv,
|
||||
SYS_execv,
|
||||
#endif
|
||||
SYS_execve,
|
||||
SYS_execve,
|
||||
#ifdef SYS_execveat
|
||||
SYS_execveat,
|
||||
SYS_execveat,
|
||||
#endif
|
||||
#ifdef SYS_exec_with_loader
|
||||
SYS_exec_with_loader,
|
||||
SYS_exec_with_loader,
|
||||
#endif
|
||||
#ifdef SYS_osf_execve
|
||||
SYS_osf_execve,
|
||||
SYS_osf_execve,
|
||||
#endif
|
||||
#ifdef SYS_uselib
|
||||
SYS_uselib,
|
||||
SYS_uselib,
|
||||
#endif
|
||||
#ifdef SYS_unlink
|
||||
SYS_unlink,
|
||||
SYS_unlink,
|
||||
#endif
|
||||
SYS_unlinkat,
|
||||
SYS_unlinkat,
|
||||
#ifdef SYS_chmod
|
||||
SYS_chmod,
|
||||
SYS_chmod,
|
||||
#endif
|
||||
SYS_fchmod,SYS_fchmodat,
|
||||
SYS_fchmod, SYS_fchmodat,
|
||||
#ifdef SYS_chown
|
||||
SYS_chown,
|
||||
SYS_chown,
|
||||
#endif
|
||||
#ifdef SYS_chown32
|
||||
SYS_chown32,
|
||||
SYS_chown32,
|
||||
#endif
|
||||
SYS_fchown,
|
||||
SYS_fchown,
|
||||
#ifdef SYS_fchown32
|
||||
SYS_fchown32,
|
||||
SYS_fchown32,
|
||||
#endif
|
||||
#ifdef SYS_lchown
|
||||
SYS_lchown,
|
||||
SYS_lchown,
|
||||
#endif
|
||||
#ifdef SYS_lchown32
|
||||
SYS_lchown32,
|
||||
SYS_lchown32,
|
||||
#endif
|
||||
SYS_fchownat,
|
||||
SYS_fchownat,
|
||||
#ifdef SYS_symlink
|
||||
SYS_symlink,
|
||||
SYS_symlink,
|
||||
#endif
|
||||
SYS_symlinkat,
|
||||
SYS_symlinkat,
|
||||
#ifdef SYS_link
|
||||
SYS_link,
|
||||
SYS_link,
|
||||
#endif
|
||||
SYS_linkat,
|
||||
SYS_truncate,
|
||||
SYS_linkat,
|
||||
SYS_truncate,
|
||||
#ifdef SYS_truncate64
|
||||
SYS_truncate64,
|
||||
SYS_truncate64,
|
||||
#endif
|
||||
SYS_ftruncate,
|
||||
SYS_ftruncate,
|
||||
#ifdef SYS_ftruncate64
|
||||
SYS_ftruncate64,
|
||||
SYS_ftruncate64,
|
||||
#endif
|
||||
#ifdef SYS_mknod
|
||||
SYS_mknod,
|
||||
SYS_mknod,
|
||||
#endif
|
||||
SYS_mknodat,
|
||||
SYS_mknodat,
|
||||
#ifdef SYS_mkdir
|
||||
SYS_mkdir,
|
||||
SYS_mkdir,
|
||||
#endif
|
||||
SYS_mkdirat,
|
||||
SYS_mkdirat,
|
||||
#ifdef SYS_rmdir
|
||||
SYS_rmdir,
|
||||
SYS_rmdir,
|
||||
#endif
|
||||
#ifdef SYS_rename
|
||||
SYS_rename,
|
||||
SYS_rename,
|
||||
#endif
|
||||
#ifdef SYS_renameat2
|
||||
SYS_renameat2,
|
||||
SYS_renameat2,
|
||||
#endif
|
||||
#ifdef SYS_renameat
|
||||
SYS_renameat,
|
||||
SYS_renameat,
|
||||
#endif
|
||||
#ifdef SYS_readdir
|
||||
SYS_readdir,
|
||||
SYS_readdir,
|
||||
#endif
|
||||
#ifdef SYS_getdents
|
||||
SYS_getdents,
|
||||
SYS_getdents,
|
||||
#endif
|
||||
#ifdef SYS_getdents64
|
||||
SYS_getdents64,
|
||||
SYS_getdents64,
|
||||
#endif
|
||||
#ifdef SYS_process_vm_readv
|
||||
SYS_process_vm_readv,
|
||||
SYS_process_vm_readv,
|
||||
#endif
|
||||
#ifdef SYS_process_vm_writev
|
||||
SYS_process_vm_writev,
|
||||
SYS_process_vm_writev,
|
||||
#endif
|
||||
#ifdef SYS_process_madvise
|
||||
SYS_process_madvise,
|
||||
SYS_process_madvise,
|
||||
#endif
|
||||
SYS_kill, SYS_ptrace
|
||||
};
|
||||
#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls)/sizeof(*blocked_syscalls))
|
||||
SYS_kill, SYS_ptrace};
|
||||
#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls) / sizeof(*blocked_syscalls))
|
||||
|
||||
static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k)
|
||||
{
|
||||
@@ -132,13 +131,13 @@ static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf,
|
||||
static bool set_seccomp(void)
|
||||
{
|
||||
#ifdef __X32_SYSCALL_BIT
|
||||
#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT)
|
||||
#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT)
|
||||
#else
|
||||
#define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT)
|
||||
#define SECCOMP_PROG_SIZE (5 + BLOCKED_SYSCALL_COUNT)
|
||||
#endif
|
||||
struct sock_filter sockf[SECCOMP_PROG_SIZE];
|
||||
struct sock_fprog prog = { .len = SECCOMP_PROG_SIZE, .filter = sockf };
|
||||
int i,idx=0;
|
||||
struct sock_fprog prog = {.len = SECCOMP_PROG_SIZE, .filter = sockf};
|
||||
int i, idx = 0;
|
||||
|
||||
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr);
|
||||
#ifdef __X32_SYSCALL_BIT
|
||||
@@ -151,19 +150,19 @@ static bool set_seccomp(void)
|
||||
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr);
|
||||
#endif
|
||||
|
||||
/*
|
||||
// ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr
|
||||
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3, SYS_write); // special check for write call
|
||||
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_arg(0)); // fd
|
||||
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 2 + BLOCKED_SYSCALL_COUNT, 0, 2); // 1 - stdout, 2 - stderr. greater are bad
|
||||
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); // reload syscall_nr
|
||||
*/
|
||||
for(i=0 ; i<BLOCKED_SYSCALL_COUNT ; i++)
|
||||
/*
|
||||
// ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr
|
||||
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3, SYS_write); // special check for write call
|
||||
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_arg(0)); // fd
|
||||
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 2 + BLOCKED_SYSCALL_COUNT, 0, 2); // 1 - stdout, 2 - stderr. greater are bad
|
||||
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); // reload syscall_nr
|
||||
*/
|
||||
for (i = 0; i < BLOCKED_SYSCALL_COUNT; i++)
|
||||
{
|
||||
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, BLOCKED_SYSCALL_COUNT-i, 0, blocked_syscalls[i]);
|
||||
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, BLOCKED_SYSCALL_COUNT - i, 0, blocked_syscalls[i]);
|
||||
}
|
||||
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_ALLOW); // success case
|
||||
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_KILL); // fail case
|
||||
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_KILL); // fail case
|
||||
return prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) >= 0;
|
||||
}
|
||||
|
||||
@@ -174,42 +173,41 @@ bool sec_harden(void)
|
||||
DLOG_PERROR("PR_SET_NO_NEW_PRIVS(prctl)");
|
||||
return false;
|
||||
}
|
||||
#if ARCH_NR!=0
|
||||
#if ARCH_NR != 0
|
||||
if (!set_seccomp())
|
||||
{
|
||||
DLOG_PERROR("seccomp");
|
||||
if (errno==EINVAL) DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n");
|
||||
if (errno == EINVAL)
|
||||
DLOG_ERR("seccomp: this can be safely ignored if kernel does not support seccomp\n");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool checkpcap(uint64_t caps)
|
||||
{
|
||||
if (!caps) return true; // no special caps reqd
|
||||
if (!caps)
|
||||
return true; // no special caps reqd
|
||||
|
||||
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
|
||||
struct __user_cap_data_struct cd[2];
|
||||
uint32_t c0 = (uint32_t)caps;
|
||||
uint32_t c1 = (uint32_t)(caps>>32);
|
||||
uint32_t c1 = (uint32_t)(caps >> 32);
|
||||
|
||||
return !capget(&ch,cd) && (cd[0].effective & c0)==c0 && (cd[1].effective & c1)==c1;
|
||||
return !capget(&ch, cd) && (cd[0].effective & c0) == c0 && (cd[1].effective & c1) == c1;
|
||||
}
|
||||
bool setpcap(uint64_t caps)
|
||||
{
|
||||
struct __user_cap_header_struct ch = {_LINUX_CAPABILITY_VERSION_3, getpid()};
|
||||
struct __user_cap_data_struct cd[2];
|
||||
|
||||
|
||||
cd[0].effective = cd[0].permitted = (uint32_t)caps;
|
||||
cd[0].inheritable = 0;
|
||||
cd[1].effective = cd[1].permitted = (uint32_t)(caps>>32);
|
||||
cd[1].effective = cd[1].permitted = (uint32_t)(caps >> 32);
|
||||
cd[1].inheritable = 0;
|
||||
|
||||
return !capset(&ch,cd);
|
||||
return !capset(&ch, cd);
|
||||
}
|
||||
int getmaxcap(void)
|
||||
{
|
||||
@@ -221,18 +219,17 @@ int getmaxcap(void)
|
||||
fclose(F);
|
||||
}
|
||||
return maxcap;
|
||||
|
||||
}
|
||||
bool dropcaps(void)
|
||||
{
|
||||
uint64_t caps = 0;
|
||||
int maxcap = getmaxcap();
|
||||
|
||||
if (setpcap(caps|(1<<CAP_SETPCAP)))
|
||||
if (setpcap(caps | (1 << CAP_SETPCAP)))
|
||||
{
|
||||
for (int cap = 0; cap <= maxcap; cap++)
|
||||
{
|
||||
if (prctl(PR_CAPBSET_DROP, cap)<0)
|
||||
if (prctl(PR_CAPBSET_DROP, cap) < 0)
|
||||
{
|
||||
DLOG_ERR("could not drop bound cap %d\n", cap);
|
||||
DLOG_PERROR("cap_drop_bound");
|
||||
@@ -257,13 +254,11 @@ bool sec_harden(void)
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
|
||||
|
||||
bool can_drop_root(void)
|
||||
{
|
||||
#ifdef __linux__
|
||||
// has some caps
|
||||
return checkpcap((1<<CAP_SETUID)|(1<<CAP_SETGID)|(1<<CAP_SETPCAP));
|
||||
return checkpcap((1 << CAP_SETUID) | (1 << CAP_SETGID) | (1 << CAP_SETPCAP));
|
||||
#else
|
||||
// effective root
|
||||
return !geteuid();
|
||||
@@ -280,7 +275,7 @@ bool droproot(uid_t uid, gid_t gid)
|
||||
}
|
||||
#endif
|
||||
// drop all SGIDs
|
||||
if (setgroups(0,NULL))
|
||||
if (setgroups(0, NULL))
|
||||
{
|
||||
DLOG_PERROR("setgroups");
|
||||
return false;
|
||||
@@ -304,19 +299,19 @@ bool droproot(uid_t uid, gid_t gid)
|
||||
|
||||
void print_id(void)
|
||||
{
|
||||
int i,N;
|
||||
gid_t g[128];
|
||||
int i, N;
|
||||
gid_t g[128];
|
||||
|
||||
DLOG_CONDUP("Running as UID=%u GID=",getuid());
|
||||
N=getgroups(sizeof(g)/sizeof(*g),g);
|
||||
if (N>0)
|
||||
{
|
||||
for(i=0;i<N;i++)
|
||||
DLOG_CONDUP(i==(N-1) ? "%u" : "%u,", g[i]);
|
||||
DLOG_CONDUP("\n");
|
||||
}
|
||||
else
|
||||
DLOG_CONDUP("%u\n",getgid());
|
||||
DLOG_CONDUP("Running as UID=%u GID=", getuid());
|
||||
N = getgroups(sizeof(g) / sizeof(*g), g);
|
||||
if (N > 0)
|
||||
{
|
||||
for (i = 0; i < N; i++)
|
||||
DLOG_CONDUP(i == (N - 1) ? "%u" : "%u,", g[i]);
|
||||
DLOG_CONDUP("\n");
|
||||
}
|
||||
else
|
||||
DLOG_CONDUP("%u\n", getgid());
|
||||
}
|
||||
|
||||
void daemonize(void)
|
||||
|
56
tpws/sec.h
56
tpws/sec.h
@@ -22,61 +22,61 @@ bool dropcaps(void);
|
||||
|
||||
#if defined(__aarch64__)
|
||||
|
||||
# define ARCH_NR AUDIT_ARCH_AARCH64
|
||||
#define ARCH_NR AUDIT_ARCH_AARCH64
|
||||
|
||||
#elif defined(__amd64__)
|
||||
|
||||
# define ARCH_NR AUDIT_ARCH_X86_64
|
||||
#define ARCH_NR AUDIT_ARCH_X86_64
|
||||
|
||||
#elif defined(__arm__) && (defined(__ARM_EABI__) || defined(__thumb__))
|
||||
|
||||
# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define ARCH_NR AUDIT_ARCH_ARM
|
||||
# else
|
||||
# define ARCH_NR AUDIT_ARCH_ARMEB
|
||||
# endif
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define ARCH_NR AUDIT_ARCH_ARM
|
||||
#else
|
||||
#define ARCH_NR AUDIT_ARCH_ARMEB
|
||||
#endif
|
||||
|
||||
#elif defined(__i386__)
|
||||
|
||||
# define ARCH_NR AUDIT_ARCH_I386
|
||||
#define ARCH_NR AUDIT_ARCH_I386
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define ARCH_NR AUDIT_ARCH_MIPSEL
|
||||
# else
|
||||
# define ARCH_NR AUDIT_ARCH_MIPS
|
||||
# endif
|
||||
#elif _MIPS_SIM == _MIPS_SIM_ABI64
|
||||
# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define ARCH_NR AUDIT_ARCH_MIPSEL64
|
||||
# else
|
||||
# define ARCH_NR AUDIT_ARCH_MIPS64
|
||||
# endif
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define ARCH_NR AUDIT_ARCH_MIPSEL
|
||||
#else
|
||||
# error "Unsupported mips abi"
|
||||
#define ARCH_NR AUDIT_ARCH_MIPS
|
||||
#endif
|
||||
#elif _MIPS_SIM == _MIPS_SIM_ABI64
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define ARCH_NR AUDIT_ARCH_MIPSEL64
|
||||
#else
|
||||
#define ARCH_NR AUDIT_ARCH_MIPS64
|
||||
#endif
|
||||
#else
|
||||
#error "Unsupported MIPS ABI"
|
||||
#endif
|
||||
|
||||
#elif defined(__PPC64__)
|
||||
|
||||
# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define ARCH_NR AUDIT_ARCH_PPC64LE
|
||||
# else
|
||||
# define ARCH_NR AUDIT_ARCH_PPC64
|
||||
# endif
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define ARCH_NR AUDIT_ARCH_PPC64LE
|
||||
#else
|
||||
#define ARCH_NR AUDIT_ARCH_PPC64
|
||||
#endif
|
||||
|
||||
#elif defined(__PPC__)
|
||||
|
||||
# define ARCH_NR AUDIT_ARCH_PPC
|
||||
#define ARCH_NR AUDIT_ARCH_PPC
|
||||
|
||||
#elif __riscv && __riscv_xlen == 64
|
||||
|
||||
# define ARCH_NR AUDIT_ARCH_RISCV64
|
||||
#define ARCH_NR AUDIT_ARCH_RISCV64
|
||||
|
||||
#else
|
||||
|
||||
# error "Platform does not support seccomp filter yet"
|
||||
#error "Platform does not support seccomp filter yet"
|
||||
|
||||
#endif
|
||||
|
||||
|
96
tpws/socks.h
96
tpws/socks.h
@@ -3,87 +3,91 @@
|
||||
#include <stdint.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#pragma pack(push,1)
|
||||
#pragma pack(push, 1)
|
||||
|
||||
#define S4_CMD_CONNECT 1
|
||||
#define S4_CMD_BIND 2
|
||||
#define S4_CMD_CONNECT 1
|
||||
#define S4_CMD_BIND 2
|
||||
typedef struct
|
||||
{
|
||||
uint8_t ver,cmd;
|
||||
uint8_t ver, cmd;
|
||||
uint16_t port;
|
||||
uint32_t ip;
|
||||
} s4_req;
|
||||
#define S4_REQ_HEADER_VALID(r,l) (l>=sizeof(s4_req) && r->ver==4)
|
||||
#define S4_REQ_CONNECT_VALID(r,l) (S4_REQ_HEADER_VALID(r,l) && r->cmd==S4_CMD_CONNECT)
|
||||
#define S4_REQ_HEADER_VALID(r, l) (l >= sizeof(s4_req) && r->ver == 4)
|
||||
#define S4_REQ_CONNECT_VALID(r, l) (S4_REQ_HEADER_VALID(r, l) && r->cmd == S4_CMD_CONNECT)
|
||||
|
||||
#define S4_REP_OK 90
|
||||
#define S4_REP_FAILED 91
|
||||
#define S4_REP_OK 90
|
||||
#define S4_REP_FAILED 91
|
||||
typedef struct
|
||||
{
|
||||
uint8_t zero,rep;
|
||||
uint8_t zero, rep;
|
||||
uint16_t port;
|
||||
uint32_t ip;
|
||||
} s4_rep;
|
||||
|
||||
|
||||
|
||||
#define S5_AUTH_NONE 0
|
||||
#define S5_AUTH_GSSAPI 1
|
||||
#define S5_AUTH_USERPASS 2
|
||||
#define S5_AUTH_UNACCEPTABLE 0xFF
|
||||
#define S5_AUTH_NONE 0
|
||||
#define S5_AUTH_GSSAPI 1
|
||||
#define S5_AUTH_USERPASS 2
|
||||
#define S5_AUTH_UNACCEPTABLE 0xFF
|
||||
typedef struct
|
||||
{
|
||||
uint8_t ver,nmethods,methods[255];
|
||||
uint8_t ver, nmethods, methods[255];
|
||||
} s5_handshake;
|
||||
#define S5_REQ_HANDHSHAKE_VALID(r,l) (l>=3 && r->ver==5 && r->nmethods && l>=(2+r->nmethods))
|
||||
#define S5_REQ_HANDHSHAKE_VALID(r, l) (l >= 3 && r->ver == 5 && r->nmethods && l >= (2 + r->nmethods))
|
||||
typedef struct
|
||||
{
|
||||
uint8_t ver,method;
|
||||
uint8_t ver, method;
|
||||
} s5_handshake_ack;
|
||||
|
||||
#define S5_CMD_CONNECT 1
|
||||
#define S5_CMD_BIND 2
|
||||
#define S5_CMD_UDP_ASSOC 3
|
||||
#define S5_ATYP_IP4 1
|
||||
#define S5_ATYP_DOM 3
|
||||
#define S5_ATYP_IP6 4
|
||||
#define S5_CMD_CONNECT 1
|
||||
#define S5_CMD_BIND 2
|
||||
#define S5_CMD_UDP_ASSOC 3
|
||||
#define S5_ATYP_IP4 1
|
||||
#define S5_ATYP_DOM 3
|
||||
#define S5_ATYP_IP6 4
|
||||
typedef struct
|
||||
{
|
||||
uint8_t ver,cmd,rsv,atyp;
|
||||
union {
|
||||
struct {
|
||||
uint8_t ver, cmd, rsv, atyp;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
struct in_addr addr;
|
||||
uint16_t port;
|
||||
} d4;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
struct in6_addr addr;
|
||||
uint16_t port;
|
||||
} d6;
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
uint8_t len;
|
||||
char domport[255+2]; // max hostname + binary port
|
||||
char domport[255 + 2]; // max hostname + binary port
|
||||
} dd;
|
||||
};
|
||||
} s5_req;
|
||||
#define S5_REQ_HEADER_VALID(r,l) (l>=4 && r->ver==5)
|
||||
#define S5_IP46_VALID(r,l) ((r->atyp==S5_ATYP_IP4 && l>=(4+sizeof(r->d4))) || (r->atyp==S5_ATYP_IP6 && l>=(4+sizeof(r->d6))))
|
||||
#define S5_REQ_CONNECT_VALID(r,l) (S5_REQ_HEADER_VALID(r,l) && r->cmd==S5_CMD_CONNECT && (S5_IP46_VALID(r,l) || (r->atyp==S5_ATYP_DOM && l>=5 && l>=(5+r->dd.len))))
|
||||
#define S5_PORT_FROM_DD(r,l) (l>=(4+r->dd.len+2) ? ntohs(*(uint16_t*)(r->dd.domport+r->dd.len)) : 0)
|
||||
#define S5_REQ_HEADER_VALID(r, l) (l >= 4 && r->ver == 5)
|
||||
#define S5_IP46_VALID(r, l) ((r->atyp == S5_ATYP_IP4 && l >= (4 + sizeof(r->d4))) || (r->atyp == S5_ATYP_IP6 && l >= (4 + sizeof(r->d6))))
|
||||
#define S5_REQ_CONNECT_VALID(r, l) (S5_REQ_HEADER_VALID(r, l) && r->cmd == S5_CMD_CONNECT && (S5_IP46_VALID(r, l) || (r->atyp == S5_ATYP_DOM && l >= 5 && l >= (5 + r->dd.len))))
|
||||
#define S5_PORT_FROM_DD(r, l) (l >= (4 + r->dd.len + 2) ? ntohs(*(uint16_t *)(r->dd.domport + r->dd.len)) : 0)
|
||||
|
||||
#define S5_REP_OK 0
|
||||
#define S5_REP_GENERAL_FAILURE 1
|
||||
#define S5_REP_NOT_ALLOWED_BY_RULESET 2
|
||||
#define S5_REP_NETWORK_UNREACHABLE 3
|
||||
#define S5_REP_HOST_UNREACHABLE 4
|
||||
#define S5_REP_CONN_REFUSED 5
|
||||
#define S5_REP_TTL_EXPIRED 6
|
||||
#define S5_REP_COMMAND_NOT_SUPPORTED 7
|
||||
#define S5_REP_ADDR_TYPE_NOT_SUPPORTED 8
|
||||
#define S5_REP_OK 0
|
||||
#define S5_REP_GENERAL_FAILURE 1
|
||||
#define S5_REP_NOT_ALLOWED_BY_RULESET 2
|
||||
#define S5_REP_NETWORK_UNREACHABLE 3
|
||||
#define S5_REP_HOST_UNREACHABLE 4
|
||||
#define S5_REP_CONN_REFUSED 5
|
||||
#define S5_REP_TTL_EXPIRED 6
|
||||
#define S5_REP_COMMAND_NOT_SUPPORTED 7
|
||||
#define S5_REP_ADDR_TYPE_NOT_SUPPORTED 8
|
||||
typedef struct
|
||||
{
|
||||
uint8_t ver,rep,rsv,atyp;
|
||||
union {
|
||||
struct {
|
||||
uint8_t ver, rep, rsv, atyp;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
struct in_addr addr;
|
||||
uint16_t port;
|
||||
} d4;
|
||||
|
196
tpws/tamper.c
196
tpws/tamper.c
@@ -9,36 +9,40 @@
|
||||
#include <stdio.h>
|
||||
|
||||
// segment buffer has at least 5 extra bytes to extend data block
|
||||
void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags)
|
||||
void tamper_out(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size, size_t *split_pos, uint8_t *split_flags)
|
||||
{
|
||||
uint8_t *p, *pp, *pHost = NULL;
|
||||
size_t method_len = 0, pos;
|
||||
const char *method;
|
||||
bool bBypass = false, bHaveHost = false, bHostExcluded = false;
|
||||
char *pc, Host[256];
|
||||
|
||||
|
||||
DBGPRINT("tamper_out\n");
|
||||
|
||||
*split_pos=0;
|
||||
*split_flags=0;
|
||||
*split_pos = 0;
|
||||
*split_flags = 0;
|
||||
|
||||
if ((method = HttpMethod(segment,*size)))
|
||||
if ((method = HttpMethod(segment, *size)))
|
||||
{
|
||||
method_len = strlen(method)-2;
|
||||
VPRINT("Data block looks like http request start : %s\n", method);
|
||||
if (!ctrack->l7proto) ctrack->l7proto=HTTP;
|
||||
method_len = strlen(method) - 2;
|
||||
VPRINT("Data block looks like HTTP request start : %s\n", method);
|
||||
if (!ctrack->l7proto)
|
||||
ctrack->l7proto = HTTP;
|
||||
// cpu saving : we search host only if and when required. we do not research host every time we need its position
|
||||
if ((params.hostlist || params.hostlist_exclude) && HttpFindHost(&pHost,segment,*size))
|
||||
if ((params.hostlist || params.hostlist_exclude) && HttpFindHost(&pHost, segment, *size))
|
||||
{
|
||||
p = pHost + 5;
|
||||
while (p < (segment + *size) && (*p == ' ' || *p == '\t')) p++;
|
||||
while (p < (segment + *size) && (*p == ' ' || *p == '\t'))
|
||||
p++;
|
||||
pp = p;
|
||||
while (pp < (segment + *size) && (pp - p) < (sizeof(Host) - 1) && *pp != '\r' && *pp != '\n') pp++;
|
||||
while (pp < (segment + *size) && (pp - p) < (sizeof(Host) - 1) && *pp != '\r' && *pp != '\n')
|
||||
pp++;
|
||||
memcpy(Host, p, pp - p);
|
||||
Host[pp - p] = '\0';
|
||||
bHaveHost = true;
|
||||
VPRINT("Requested Host is : %s\n", Host);
|
||||
for(pc = Host; *pc; pc++) *pc=tolower(*pc);
|
||||
for (pc = Host; *pc; pc++)
|
||||
*pc = tolower(*pc);
|
||||
bBypass = !HostlistCheck(Host, &bHostExcluded);
|
||||
}
|
||||
if (!bBypass)
|
||||
@@ -48,7 +52,8 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
||||
p = pp = segment;
|
||||
while ((p = memmem(p, segment + *size - p, "\r\n", 2)))
|
||||
{
|
||||
*p = '\n'; p++;
|
||||
*p = '\n';
|
||||
p++;
|
||||
memmove(p, p + 1, segment + *size - p - 1);
|
||||
(*size)--;
|
||||
if (pp == (p - 1))
|
||||
@@ -61,13 +66,14 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
||||
}
|
||||
pHost = NULL; // invalidate
|
||||
}
|
||||
if (params.methodeol && (*size+1+!params.unixeol)<=segment_buffer_size)
|
||||
if (params.methodeol && (*size + 1 + !params.unixeol) <= segment_buffer_size)
|
||||
{
|
||||
VPRINT("Adding EOL before method\n");
|
||||
if (params.unixeol)
|
||||
{
|
||||
memmove(segment + 1, segment, *size);
|
||||
(*size)++;;
|
||||
(*size)++;
|
||||
;
|
||||
segment[0] = '\n';
|
||||
}
|
||||
else
|
||||
@@ -79,39 +85,41 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
||||
}
|
||||
pHost = NULL; // invalidate
|
||||
}
|
||||
if (params.methodspace && *size<segment_buffer_size)
|
||||
if (params.methodspace && *size < segment_buffer_size)
|
||||
{
|
||||
// we only work with data blocks looking as HTTP query, so method is at the beginning
|
||||
VPRINT("Adding extra space after method\n");
|
||||
p = segment + method_len + 1;
|
||||
pos = method_len + 1;
|
||||
memmove(p + 1, p, *size - pos);
|
||||
*p = ' '; // insert extra space
|
||||
*p = ' '; // insert extra space
|
||||
(*size)++; // block will grow by 1 byte
|
||||
if (pHost) pHost++; // Host: position will move by 1 byte
|
||||
if (pHost)
|
||||
pHost++; // Host: position will move by 1 byte
|
||||
}
|
||||
if ((params.hostdot || params.hosttab) && *size<segment_buffer_size && HttpFindHost(&pHost,segment,*size))
|
||||
if ((params.hostdot || params.hosttab) && *size < segment_buffer_size && HttpFindHost(&pHost, segment, *size))
|
||||
{
|
||||
p = pHost + 5;
|
||||
while (p < (segment + *size) && *p != '\r' && *p != '\n') p++;
|
||||
while (p < (segment + *size) && *p != '\r' && *p != '\n')
|
||||
p++;
|
||||
if (p < (segment + *size))
|
||||
{
|
||||
pos = p - segment;
|
||||
VPRINT("Adding %s to host name at pos %zu\n", params.hostdot ? "dot" : "tab", pos);
|
||||
memmove(p + 1, p, *size - pos);
|
||||
*p = params.hostdot ? '.' : '\t'; // insert dot or tab
|
||||
(*size)++; // block will grow by 1 byte
|
||||
(*size)++; // block will grow by 1 byte
|
||||
}
|
||||
}
|
||||
if (params.domcase && HttpFindHost(&pHost,segment,*size))
|
||||
if (params.domcase && HttpFindHost(&pHost, segment, *size))
|
||||
{
|
||||
p = pHost + 5;
|
||||
pos = p - segment;
|
||||
VPRINT("Mixing domain case at pos %zu\n",pos);
|
||||
VPRINT("Mixing domain case at pos %zu\n", pos);
|
||||
for (; p < (segment + *size) && *p != '\r' && *p != '\n'; p++)
|
||||
*p = (((size_t)p) & 1) ? tolower(*p) : toupper(*p);
|
||||
}
|
||||
if (params.hostnospace && HttpFindHost(&pHost,segment,*size) && (pHost+5)<(segment+*size) && pHost[5] == ' ')
|
||||
if (params.hostnospace && HttpFindHost(&pHost, segment, *size) && (pHost + 5) < (segment + *size) && pHost[5] == ' ')
|
||||
{
|
||||
p = pHost + 6;
|
||||
pos = p - segment;
|
||||
@@ -119,78 +127,83 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
||||
memmove(p - 1, p, *size - pos);
|
||||
(*size)--; // block will shrink by 1 byte
|
||||
}
|
||||
if (params.hostcase && HttpFindHost(&pHost,segment,*size))
|
||||
if (params.hostcase && HttpFindHost(&pHost, segment, *size))
|
||||
{
|
||||
VPRINT("Changing 'Host:' => '%c%c%c%c:' at pos %td\n", params.hostspell[0], params.hostspell[1], params.hostspell[2], params.hostspell[3], pHost - segment);
|
||||
memcpy(pHost, params.hostspell, 4);
|
||||
}
|
||||
if (params.hostpad && HttpFindHost(&pHost,segment,*size))
|
||||
if (params.hostpad && HttpFindHost(&pHost, segment, *size))
|
||||
{
|
||||
// add : XXXXX: <padding?[\r\n|\n]
|
||||
char s[8];
|
||||
size_t hsize = params.unixeol ? 8 : 9;
|
||||
size_t hostpad = params.hostpad<hsize ? hsize : params.hostpad;
|
||||
size_t hostpad = params.hostpad < hsize ? hsize : params.hostpad;
|
||||
|
||||
if ((hsize+*size)>segment_buffer_size)
|
||||
if ((hsize + *size) > segment_buffer_size)
|
||||
VPRINT("could not add host padding : buffer too small\n");
|
||||
else
|
||||
{
|
||||
if ((hostpad+*size)>segment_buffer_size)
|
||||
if ((hostpad + *size) > segment_buffer_size)
|
||||
{
|
||||
hostpad=segment_buffer_size-*size;
|
||||
hostpad = segment_buffer_size - *size;
|
||||
VPRINT("host padding reduced to %zu bytes : buffer too small\n", hostpad);
|
||||
}
|
||||
else
|
||||
VPRINT("host padding with %zu bytes\n", hostpad);
|
||||
|
||||
|
||||
p = pHost;
|
||||
pos = p - segment;
|
||||
memmove(p + hostpad, p, *size - pos);
|
||||
(*size) += hostpad;
|
||||
while(hostpad)
|
||||
while (hostpad)
|
||||
{
|
||||
#define MAX_HDR_SIZE 2048
|
||||
size_t padsize = hostpad > hsize ? hostpad-hsize : 0;
|
||||
if (padsize>MAX_HDR_SIZE) padsize=MAX_HDR_SIZE;
|
||||
#define MAX_HDR_SIZE 2048
|
||||
size_t padsize = hostpad > hsize ? hostpad - hsize : 0;
|
||||
if (padsize > MAX_HDR_SIZE)
|
||||
padsize = MAX_HDR_SIZE;
|
||||
// if next header would be too small then add extra padding to the current one
|
||||
if ((hostpad-padsize-hsize)<hsize) padsize+=hostpad-padsize-hsize;
|
||||
snprintf(s,sizeof(s),"%c%04x: ", 'a'+rand()%('z'-'a'+1), rand() & 0xFFFF);
|
||||
memcpy(p,s,7);
|
||||
p+=7;
|
||||
memset(p,'a'+rand()%('z'-'a'+1),padsize);
|
||||
p+=padsize;
|
||||
if ((hostpad - padsize - hsize) < hsize)
|
||||
padsize += hostpad - padsize - hsize;
|
||||
snprintf(s, sizeof(s), "%c%04x: ", 'a' + rand() % ('z' - 'a' + 1), rand() & 0xFFFF);
|
||||
memcpy(p, s, 7);
|
||||
p += 7;
|
||||
memset(p, 'a' + rand() % ('z' - 'a' + 1), padsize);
|
||||
p += padsize;
|
||||
if (params.unixeol)
|
||||
*p++='\n';
|
||||
*p++ = '\n';
|
||||
else
|
||||
{
|
||||
*p++='\r';
|
||||
*p++='\n';
|
||||
*p++ = '\r';
|
||||
*p++ = '\n';
|
||||
}
|
||||
hostpad-=hsize+padsize;
|
||||
hostpad -= hsize + padsize;
|
||||
}
|
||||
pHost = NULL; // invalidate
|
||||
}
|
||||
}
|
||||
*split_pos = HttpPos(params.split_http_req, params.split_pos, segment, *size);
|
||||
if (params.disorder_http) *split_flags |= SPLIT_FLAG_DISORDER;
|
||||
if (params.oob_http) *split_flags |= SPLIT_FLAG_OOB;
|
||||
if (params.disorder_http)
|
||||
*split_flags |= SPLIT_FLAG_DISORDER;
|
||||
if (params.oob_http)
|
||||
*split_flags |= SPLIT_FLAG_OOB;
|
||||
}
|
||||
else
|
||||
{
|
||||
VPRINT("Not acting on this request\n");
|
||||
}
|
||||
}
|
||||
else if (IsTLSClientHello(segment,*size,false))
|
||||
else if (IsTLSClientHello(segment, *size, false))
|
||||
{
|
||||
size_t tpos=0,spos=0;
|
||||
|
||||
if (!ctrack->l7proto) ctrack->l7proto=TLS;
|
||||
size_t tpos = 0, spos = 0;
|
||||
|
||||
if (!ctrack->l7proto)
|
||||
ctrack->l7proto = TLS;
|
||||
|
||||
VPRINT("packet contains TLS ClientHello\n");
|
||||
// we need host only if hostlist is present
|
||||
if ((params.hostlist || params.hostlist_exclude) && TLSHelloExtractHost((uint8_t*)segment,*size,Host,sizeof(Host),false))
|
||||
if ((params.hostlist || params.hostlist_exclude) && TLSHelloExtractHost((uint8_t *)segment, *size, Host, sizeof(Host), false))
|
||||
{
|
||||
VPRINT("hostname: %s\n",Host);
|
||||
VPRINT("hostname: %s\n", Host);
|
||||
bHaveHost = true;
|
||||
bBypass = !HostlistCheck(Host, &bHostExcluded);
|
||||
}
|
||||
@@ -202,52 +215,59 @@ void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,si
|
||||
{
|
||||
spos = TLSPos(params.split_tls, params.split_pos, segment, *size, 0);
|
||||
|
||||
if ((5+*size)<=segment_buffer_size)
|
||||
if ((5 + *size) <= segment_buffer_size)
|
||||
{
|
||||
tpos = TLSPos(params.tlsrec, params.tlsrec_pos+5, segment, *size, 0);
|
||||
if (tpos>5)
|
||||
tpos = TLSPos(params.tlsrec, params.tlsrec_pos + 5, segment, *size, 0);
|
||||
if (tpos > 5)
|
||||
{
|
||||
// construct 2 TLS records from one
|
||||
uint16_t l = pntoh16(segment+3); // length
|
||||
if (l>=2)
|
||||
uint16_t l = pntoh16(segment + 3); // length
|
||||
if (l >= 2)
|
||||
{
|
||||
// length is checked in IsTLSClientHello and cannot exceed buffer size
|
||||
if ((tpos-5)>=l) tpos=5+1;
|
||||
VPRINT("making 2 TLS records at pos %zu\n",tpos);
|
||||
memmove(segment+tpos+5,segment+tpos,*size-tpos);
|
||||
if ((tpos - 5) >= l)
|
||||
tpos = 5 + 1;
|
||||
VPRINT("making 2 TLS records at pos %zu\n", tpos);
|
||||
memmove(segment + tpos + 5, segment + tpos, *size - tpos);
|
||||
segment[tpos] = segment[0];
|
||||
segment[tpos+1] = segment[1];
|
||||
segment[tpos+2] = segment[2];
|
||||
phton16(segment+tpos+3,l-(tpos-5));
|
||||
phton16(segment+3,tpos-5);
|
||||
segment[tpos + 1] = segment[1];
|
||||
segment[tpos + 2] = segment[2];
|
||||
phton16(segment + tpos + 3, l - (tpos - 5));
|
||||
phton16(segment + 3, tpos - 5);
|
||||
*size += 5;
|
||||
// split pos present and it is not before tlsrec split. increase split pos by tlsrec header size (5 bytes)
|
||||
if (spos && spos>=tpos) spos+=5;
|
||||
if (spos && spos >= tpos)
|
||||
spos += 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (spos && spos < *size)
|
||||
{
|
||||
VPRINT("split pos %zu\n",spos);
|
||||
VPRINT("split pos %zu\n", spos);
|
||||
*split_pos = spos;
|
||||
}
|
||||
|
||||
if (params.disorder_tls) *split_flags |= SPLIT_FLAG_DISORDER;
|
||||
if (params.oob_tls) *split_flags |= SPLIT_FLAG_OOB;
|
||||
if (params.disorder_tls)
|
||||
*split_flags |= SPLIT_FLAG_DISORDER;
|
||||
if (params.oob_tls)
|
||||
*split_flags |= SPLIT_FLAG_OOB;
|
||||
}
|
||||
}
|
||||
else if (params.split_any_protocol && params.split_pos < *size)
|
||||
*split_pos = params.split_pos;
|
||||
|
||||
|
||||
if (bHaveHost && bBypass && !bHostExcluded && *params.hostlist_auto_filename)
|
||||
{
|
||||
DBGPRINT("tamper_out put hostname : %s\n", Host);
|
||||
if (ctrack->hostname) free(ctrack->hostname);
|
||||
ctrack->hostname=strdup(Host);
|
||||
if (ctrack->hostname)
|
||||
free(ctrack->hostname);
|
||||
ctrack->hostname = strdup(Host);
|
||||
}
|
||||
if (params.disorder) *split_flags |= SPLIT_FLAG_DISORDER;
|
||||
if (params.oob) *split_flags |= SPLIT_FLAG_OOB;
|
||||
if (params.disorder)
|
||||
*split_flags |= SPLIT_FLAG_DISORDER;
|
||||
if (params.oob)
|
||||
*split_flags |= SPLIT_FLAG_OOB;
|
||||
}
|
||||
|
||||
static void auto_hostlist_reset_fail_counter(const char *hostname)
|
||||
@@ -255,7 +275,7 @@ static void auto_hostlist_reset_fail_counter(const char *hostname)
|
||||
if (hostname)
|
||||
{
|
||||
hostfail_pool *fail_counter;
|
||||
|
||||
|
||||
fail_counter = HostFailPoolFind(params.hostlist_auto_fail_counters, hostname);
|
||||
if (fail_counter)
|
||||
{
|
||||
@@ -287,9 +307,9 @@ static void auto_hostlist_failed(const char *hostname)
|
||||
{
|
||||
VPRINT("auto hostlist : fail threshold reached. adding %s to auto hostlist\n", hostname);
|
||||
HostFailPoolDel(¶ms.hostlist_auto_fail_counters, fail_counter);
|
||||
|
||||
|
||||
VPRINT("auto hostlist : rechecking %s to avoid duplicates\n", hostname);
|
||||
bool bExcluded=false;
|
||||
bool bExcluded = false;
|
||||
if (!HostlistCheck(hostname, &bExcluded) && !bExcluded)
|
||||
{
|
||||
VPRINT("auto hostlist : adding %s\n", hostname);
|
||||
@@ -314,9 +334,9 @@ static void auto_hostlist_failed(const char *hostname)
|
||||
}
|
||||
}
|
||||
|
||||
void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size)
|
||||
void tamper_in(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size)
|
||||
{
|
||||
bool bFail=false;
|
||||
bool bFail = false;
|
||||
|
||||
DBGPRINT("tamper_in hostname=%s\n", ctrack->hostname);
|
||||
|
||||
@@ -324,9 +344,9 @@ void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,siz
|
||||
{
|
||||
HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters);
|
||||
|
||||
if (ctrack->l7proto==HTTP && ctrack->hostname)
|
||||
if (ctrack->l7proto == HTTP && ctrack->hostname)
|
||||
{
|
||||
if (IsHttpReply(segment,*size))
|
||||
if (IsHttpReply(segment, *size))
|
||||
{
|
||||
VPRINT("incoming HTTP reply detected for hostname %s\n", ctrack->hostname);
|
||||
bFail = HttpReplyLooksLikeDPIRedirect(segment, *size, ctrack->hostname);
|
||||
@@ -343,11 +363,11 @@ void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,siz
|
||||
// received not http reply. do not monitor this connection anymore
|
||||
VPRINT("incoming unknown HTTP data detected for hostname %s\n", ctrack->hostname);
|
||||
}
|
||||
if (bFail) auto_hostlist_failed(ctrack->hostname);
|
||||
|
||||
if (bFail)
|
||||
auto_hostlist_failed(ctrack->hostname);
|
||||
}
|
||||
if (!bFail) auto_hostlist_reset_fail_counter(ctrack->hostname);
|
||||
|
||||
if (!bFail)
|
||||
auto_hostlist_reset_fail_counter(ctrack->hostname);
|
||||
}
|
||||
ctrack->bTamperInCutoff = true;
|
||||
}
|
||||
@@ -356,7 +376,8 @@ void rst_in(t_ctrack *ctrack)
|
||||
{
|
||||
DBGPRINT("rst_in hostname=%s\n", ctrack->hostname);
|
||||
|
||||
if (!*params.hostlist_auto_filename) return;
|
||||
if (!*params.hostlist_auto_filename)
|
||||
return;
|
||||
|
||||
HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters);
|
||||
|
||||
@@ -371,7 +392,8 @@ void hup_out(t_ctrack *ctrack)
|
||||
{
|
||||
DBGPRINT("hup_out hostname=%s\n", ctrack->hostname);
|
||||
|
||||
if (!*params.hostlist_auto_filename) return;
|
||||
if (!*params.hostlist_auto_filename)
|
||||
return;
|
||||
|
||||
HostFailPoolPurgeRateLimited(¶ms.hostlist_auto_fail_counters);
|
||||
|
||||
|
@@ -4,10 +4,15 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define SPLIT_FLAG_DISORDER 0x01
|
||||
#define SPLIT_FLAG_OOB 0x02
|
||||
#define SPLIT_FLAG_DISORDER 0x01
|
||||
#define SPLIT_FLAG_OOB 0x02
|
||||
|
||||
typedef enum {UNKNOWN=0, HTTP, TLS} t_l7proto;
|
||||
typedef enum
|
||||
{
|
||||
UNKNOWN = 0,
|
||||
HTTP,
|
||||
TLS
|
||||
} t_l7proto;
|
||||
typedef struct
|
||||
{
|
||||
// common state
|
||||
@@ -17,8 +22,8 @@ typedef struct
|
||||
char *hostname;
|
||||
} t_ctrack;
|
||||
|
||||
void tamper_out(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags);
|
||||
void tamper_in(t_ctrack *ctrack, uint8_t *segment,size_t segment_buffer_size,size_t *size);
|
||||
void tamper_out(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size, size_t *split_pos, uint8_t *split_flags);
|
||||
void tamper_in(t_ctrack *ctrack, uint8_t *segment, size_t segment_buffer_size, size_t *size);
|
||||
// connection reset by remote leg
|
||||
void rst_in(t_ctrack *ctrack);
|
||||
// local leg closed connection (timeout waiting response ?)
|
||||
|
673
tpws/tpws.c
673
tpws/tpws.c
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __linux__
|
||||
#define SPLICE_PRESENT
|
||||
#define SPLICE_PRESENT
|
||||
#endif
|
||||
|
||||
#include <sys/param.h>
|
||||
|
1082
tpws/tpws_conn.c
1082
tpws/tpws_conn.c
File diff suppressed because it is too large
Load Diff
@@ -10,21 +10,22 @@
|
||||
|
||||
#define BACKLOG 10
|
||||
#define MAX_EPOLL_EVENTS 64
|
||||
#define IP_TRANSPARENT 19 //So that application compiles on OpenWRT
|
||||
#define IP_TRANSPARENT 19 // So that application compiles on OpenWrt
|
||||
#define SPLICE_LEN 65536
|
||||
#define DEFAULT_MAX_CONN 512
|
||||
#define DEFAULT_MAX_ORPHAN_TIME 5
|
||||
#define DEFAULT_TCP_USER_TIMEOUT_LOCAL 10
|
||||
#define DEFAULT_TCP_USER_TIMEOUT_REMOTE 20
|
||||
#define DEFAULT_MAX_CONN 512
|
||||
#define DEFAULT_MAX_ORPHAN_TIME 5
|
||||
#define DEFAULT_TCP_USER_TIMEOUT_LOCAL 10
|
||||
#define DEFAULT_TCP_USER_TIMEOUT_REMOTE 20
|
||||
|
||||
int event_loop(const int *listen_fd, size_t listen_fd_ct);
|
||||
|
||||
//Three different states of a connection
|
||||
enum{
|
||||
CONN_UNAVAILABLE=0, // connecting
|
||||
CONN_AVAILABLE, // operational
|
||||
CONN_RDHUP, // received RDHUP, only sending unsent buffers. more RDHUPs are blocked
|
||||
CONN_CLOSED // will be deleted soon
|
||||
// Three different states of a connection
|
||||
enum
|
||||
{
|
||||
CONN_UNAVAILABLE = 0, // connecting
|
||||
CONN_AVAILABLE, // operational
|
||||
CONN_RDHUP, // received RDHUP, only sending unsent buffers. more RDHUPs are blocked
|
||||
CONN_CLOSED // will be deleted soon
|
||||
};
|
||||
typedef uint8_t conn_state_t;
|
||||
|
||||
@@ -34,13 +35,14 @@ typedef uint8_t conn_state_t;
|
||||
struct send_buffer
|
||||
{
|
||||
uint8_t *data;
|
||||
size_t len,pos;
|
||||
size_t len, pos;
|
||||
int ttl, flags;
|
||||
};
|
||||
typedef struct send_buffer send_buffer_t;
|
||||
|
||||
enum{
|
||||
CONN_TYPE_TRANSPARENT=0,
|
||||
enum
|
||||
{
|
||||
CONN_TYPE_TRANSPARENT = 0,
|
||||
CONN_TYPE_SOCKS
|
||||
};
|
||||
typedef uint8_t conn_type_t;
|
||||
@@ -48,8 +50,8 @@ typedef uint8_t conn_type_t;
|
||||
struct tproxy_conn
|
||||
{
|
||||
bool listener; // true - listening socket. false = connecion socket
|
||||
bool remote; // false - accepted, true - connected
|
||||
int efd; // epoll fd
|
||||
bool remote; // false - accepted, true - connected
|
||||
int efd; // epoll fd
|
||||
int fd;
|
||||
int splice_pipe[2];
|
||||
conn_state_t state;
|
||||
@@ -59,8 +61,9 @@ struct tproxy_conn
|
||||
time_t orphan_since;
|
||||
|
||||
// socks5 state machine
|
||||
enum {
|
||||
S_WAIT_HANDSHAKE=0,
|
||||
enum
|
||||
{
|
||||
S_WAIT_HANDSHAKE = 0,
|
||||
S_WAIT_REQUEST,
|
||||
S_WAIT_RESOLVE,
|
||||
S_WAIT_CONNECTION,
|
||||
@@ -70,11 +73,11 @@ struct tproxy_conn
|
||||
struct resolve_item *socks_ri;
|
||||
|
||||
// these value are used in flow control. we do not use ET (edge triggered) polling
|
||||
// if we dont disable notifications they will come endlessly until condition becomes false and will eat all cpu time
|
||||
bool bFlowIn,bFlowOut, bShutdown, bFlowInPrev,bFlowOutPrev, bPrevRdhup;
|
||||
// if we don't disable notifications they will come endlessly until condition becomes false and will eat all cpu time
|
||||
bool bFlowIn, bFlowOut, bShutdown, bFlowInPrev, bFlowOutPrev, bPrevRdhup;
|
||||
|
||||
// total read,write
|
||||
uint64_t trd,twr, tnrd;
|
||||
uint64_t trd, twr, tnrd;
|
||||
// number of epoll_wait events
|
||||
unsigned int event_count;
|
||||
|
||||
@@ -94,14 +97,14 @@ struct tproxy_conn
|
||||
|
||||
t_ctrack track;
|
||||
|
||||
//Create the struct which contains ptrs to next/prev element
|
||||
TAILQ_ENTRY(tproxy_conn) conn_ptrs;
|
||||
// Create the struct which contains ptrs to next/prev element
|
||||
TAILQ_ENTRY(tproxy_conn)
|
||||
conn_ptrs;
|
||||
};
|
||||
typedef struct tproxy_conn tproxy_conn_t;
|
||||
|
||||
//Define the struct tailhead (code in sys/queue.h is quite intuitive)
|
||||
//Use tail queue for efficient delete
|
||||
// Define the struct tailhead (code in sys/queue.h is quite intuitive)
|
||||
// Use tail queue for efficient delete
|
||||
TAILQ_HEAD(tailhead, tproxy_conn);
|
||||
|
||||
|
||||
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf);
|
||||
|
1880
tpws/uthash.h
1880
tpws/uthash.h
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user