From 939f0c7d3f09fb1a2a103cb4f85d5b66b29dc008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jerry=20Lundstr=C3=B6m?= Date: Fri, 4 May 2018 12:49:36 +0200 Subject: [PATCH] Client - `core.compat`: - Add `struct sockaddr_storage` - Check that we found all types - `output.tcpcli`: Issue #47: Add `connect()` and `nonblocking()` - `output.udpcli`: - Issue #46: Add `connect()` and `nonblocking()` - Use `struct sockaddr_storage` --- configure.ac | 8 ++-- src/Makefile.am | 4 +- src/core/compat.c | 25 ++++++++++ src/gen-compat.lua | 22 +++++++-- src/gen-makefile.sh | 2 + src/output/tcpcli.c | 102 +++++++++++++++++++++++++++-------------- src/output/tcpcli.hh | 5 +- src/output/tcpcli.lua | 41 +++++++++++++++-- src/output/udpcli.c | 103 ++++++++++++++++++++++++++++-------------- src/output/udpcli.h | 3 ++ src/output/udpcli.hh | 10 ++-- src/output/udpcli.lua | 41 +++++++++++++++-- 12 files changed, 277 insertions(+), 89 deletions(-) create mode 100644 src/core/compat.c diff --git a/configure.ac b/configure.ac index db51c94f..8c5c1222 100644 --- a/configure.ac +++ b/configure.ac @@ -64,9 +64,11 @@ fi # Checks for sizes AC_CHECK_SIZEOF([void*]) -AC_CHECK_SIZEOF([pthread_t]) -AC_CHECK_SIZEOF([pthread_mutex_t]) -AC_CHECK_SIZEOF([pthread_cond_t]) +AC_CHECK_SIZEOF([pthread_t],,[#include ]) +AC_CHECK_SIZEOF([pthread_mutex_t],,[#include ]) +AC_CHECK_SIZEOF([pthread_cond_t],,[#include ]) +AC_CHECK_SIZEOF([struct sockaddr_storage],,[#include +#include ]) # Output Makefiles AC_CONFIG_FILES([ diff --git a/src/Makefile.am b/src/Makefile.am index 4f21e6ae..2718ce76 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,6 +28,8 @@ AM_CFLAGS = -I$(srcdir) \ EXTRA_DIST = gen-manpage.lua gen-compat.lua dnsjit.1in +BUILT_SOURCES = core/compat.hh + bin_PROGRAMS = dnsjit dnsjit_SOURCES = dnsjit.c globals.c \ @@ -43,7 +45,7 @@ lua_objects = core.luao lib.luao input.luao filter.luao output.luao dnsjit_LDADD = $(PTHREAD_LIBS) $(luajit_LIBS) # C source and headers -dnsjit_SOURCES += core/producer.c core/log.c core/receiver.c core/object.c core/object/ip.c core/object/tcp.c core/object/pcap.c core/object/dns.c core/object/icmp6.c core/object/ieee802.c core/object/udp.c core/object/loop.c core/object/packet.c core/object/ip6.c core/object/gre.c core/object/linuxsll.c core/object/icmp.c core/object/null.c core/object/ether.c core/tracking.c core/mutex.c lib/clock.c input/zero.c input/pcap.c input/fpcap.c input/mmpcap.c input/pcapthread.c filter/lua.c filter/split.c filter/thread.c filter/timing.c filter/coro.c filter/layer.c output/udpcli.c output/cpool.c output/tcpcli.c output/cpool/client_pool.c output/cpool/client.c output/null.c +dnsjit_SOURCES += core/producer.c core/log.c core/receiver.c core/object.c core/object/ip.c core/object/tcp.c core/object/pcap.c core/object/dns.c core/object/icmp6.c core/object/ieee802.c core/object/udp.c core/object/loop.c core/object/packet.c core/object/ip6.c core/object/gre.c core/object/linuxsll.c core/object/icmp.c core/object/null.c core/object/ether.c core/tracking.c core/mutex.c core/compat.c lib/clock.c input/zero.c input/pcap.c input/fpcap.c input/mmpcap.c input/pcapthread.c filter/lua.c filter/split.c filter/thread.c filter/timing.c filter/coro.c filter/layer.c output/udpcli.c output/cpool.c output/tcpcli.c output/cpool/client_pool.c output/cpool/client.c output/null.c dist_dnsjit_SOURCES += core/mutex.h core/receiver.h core/object.h core/log.h core/timespec.h core/producer.h core/tracking.h core/object/icmp.h core/object/ip.h core/object/loop.h core/object/dns.h core/object/ip6.h core/object/null.h core/object/tcp.h core/object/udp.h core/object/packet.h core/object/icmp6.h core/object/ether.h core/object/pcap.h core/object/ieee802.h core/object/linuxsll.h core/object/gre.h lib/clock.h input/zero.h input/fpcap.h input/pcap.h input/mmpcap.h input/pcapthread.h filter/lua.h filter/split.h filter/layer.h filter/timing.h filter/thread.h filter/coro.h output/null.h output/cpool/client_pool.h output/cpool/client.h output/cpool.h output/tcpcli.h output/udpcli.h # Lua headers diff --git a/src/core/compat.c b/src/core/compat.c new file mode 100644 index 00000000..dc587847 --- /dev/null +++ b/src/core/compat.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018, OARC, Inc. + * All rights reserved. + * + * This file is part of dnsjit. + * + * dnsjit is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * dnsjit is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with dnsjit. If not, see . + */ + +#include "config.h" + +#include + +#include "core/compat.hh" diff --git a/src/gen-compat.lua b/src/gen-compat.lua index ac832fea..ca20071e 100644 --- a/src/gen-compat.lua +++ b/src/gen-compat.lua @@ -1,8 +1,22 @@ for line in io.lines("config.h") do - local n,s = line:match("define SIZEOF_(PTHREAD%S*)_T (%d+)") + local n, s = line:match("define SIZEOF_(%S*) (%d+)") if n and s then - s = math.ceil(s / 8) - n = n:lower() - print("typedef struct "..n.." { uint64_t a["..s.."]; } "..n.."_t;") + if n:match("^PTHREAD") then + s = math.ceil(s / 8) + print("#if !defined(SIZEOF_"..n..") || SIZEOF_"..n.." == 0") + print("#error \""..n.." is undefined or zero\"") + print("#endif") + n = n:lower() + print("typedef struct "..n:sub(1,-3).." { uint64_t a["..s.."]; } "..n..";") + elseif n:match("^STRUCT") then + n = n:match("^STRUCT_(%S*)") + if n == "SOCKADDR_STORAGE" then + print("#if !defined(SIZEOF_STRUCT_"..n..") || SIZEOF_STRUCT_"..n.." == 0") + print("#error \""..n.." is undefined or zero\"") + print("#endif") + n = n:lower() + print("struct "..n.." { uint8_t a["..s.."]; };") + end + end end end diff --git a/src/gen-makefile.sh b/src/gen-makefile.sh index 828b9f5d..dfc77a57 100755 --- a/src/gen-makefile.sh +++ b/src/gen-makefile.sh @@ -30,6 +30,8 @@ AM_CFLAGS = -I$(srcdir) \ EXTRA_DIST = gen-manpage.lua gen-compat.lua dnsjit.1in +BUILT_SOURCES = core/compat.hh + bin_PROGRAMS = dnsjit dnsjit_SOURCES = dnsjit.c globals.c \ diff --git a/src/output/tcpcli.c b/src/output/tcpcli.c index e2c41f45..dd45b809 100644 --- a/src/output/tcpcli.c +++ b/src/output/tcpcli.c @@ -31,13 +31,12 @@ #include #include #include -#include #include static core_log_t _log = LOG_T_INIT("output.tcpcli"); static output_tcpcli_t _defaults = { LOG_T_INIT_OBJ("output.tcpcli"), - 0, 0, -1, + 0, 0, -1 }; core_log_t* output_tcpcli_log() @@ -45,18 +44,45 @@ core_log_t* output_tcpcli_log() return &_log; } -int output_tcpcli_init(output_tcpcli_t* self, const char* host, const char* port) +int output_tcpcli_init(output_tcpcli_t* self) +{ + if (!self) { + return 1; + } + + *self = _defaults; + + ldebug("init"); + + return 0; +} + +int output_tcpcli_destroy(output_tcpcli_t* self) +{ + if (!self) { + return 1; + } + + ldebug("destroy"); + + if (self->fd > -1) { + shutdown(self->fd, SHUT_RDWR); + close(self->fd); + } + + return 0; +} + +int output_tcpcli_connect(output_tcpcli_t* self, const char* host, const char* port) { struct addrinfo* addr; int err; - if (!self || !host || !port) { + if (!self || self->fd > -1 || !host || !port) { return 1; } - *self = _defaults; - - ldebug("init %s %s", host, port); + ldebug("connect %s %s", host, port); if ((err = getaddrinfo(host, port, 0, &addr))) { lcritical("getaddrinfo() %d", err); @@ -88,26 +114,50 @@ int output_tcpcli_init(output_tcpcli_t* self, const char* host, const char* port } freeaddrinfo(addr); + return 0; +} - if ((err = fcntl(self->fd, F_GETFL)) == -1 - || fcntl(self->fd, F_SETFL, err | O_NONBLOCK)) { - lcritical("fcntl failed"); +int output_tcpcli_nonblocking(output_tcpcli_t* self) +{ + int flags; + + if (!self || self->fd < 0) { + return -1; } - return 0; + flags = fcntl(self->fd, F_GETFL); + if (flags != -1) { + flags = flags & O_NONBLOCK ? 1 : 0; + } + + return flags; } -int output_tcpcli_destroy(output_tcpcli_t* self) +int output_tcpcli_set_nonblocking(output_tcpcli_t* self, int nonblocking) { - if (!self) { + int flags; + + if (!self || self->fd < 0) { return 1; } - ldebug("destroy"); + ldebug("set nonblocking %d", nonblocking); - if (self->fd > -1) { - shutdown(self->fd, SHUT_RDWR); - close(self->fd); + if ((flags = fcntl(self->fd, F_GETFL)) == -1) { + lcritical("fcntl(FL_GETFL) failed"); + return 1; + } + + if (nonblocking) { + if (fcntl(self->fd, F_SETFL, flags | O_NONBLOCK)) { + lcritical("fcntl(FL_SETFL) failed"); + return 1; + } + } else { + if (fcntl(self->fd, F_SETFL, flags & ~O_NONBLOCK)) { + lcritical("fcntl(FL_SETFL) failed"); + return 1; + } } return 0; @@ -166,29 +216,11 @@ static int _receive(void* ctx, const core_object_t* obj) continue; return 0; } - switch (errno) { - case EAGAIN: -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif - continue; - default: - break; - } self->errs++; break; } break; } - switch (errno) { - case EAGAIN: -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif - continue; - default: - break; - } self->errs++; break; } diff --git a/src/output/tcpcli.hh b/src/output/tcpcli.hh index c37ae10d..28422563 100644 --- a/src/output/tcpcli.hh +++ b/src/output/tcpcli.hh @@ -29,7 +29,10 @@ typedef struct output_tcpcli { core_log_t* output_tcpcli_log(); -int output_tcpcli_init(output_tcpcli_t* self, const char* host, const char* port); +int output_tcpcli_init(output_tcpcli_t* self); int output_tcpcli_destroy(output_tcpcli_t* self); +int output_tcpcli_connect(output_tcpcli_t* self, const char* host, const char* port); +int output_tcpcli_nonblocking(output_tcpcli_t* self); +int output_tcpcli_set_nonblocking(output_tcpcli_t* self, int nonblocking); core_receiver_t output_tcpcli_receiver(); diff --git a/src/output/tcpcli.lua b/src/output/tcpcli.lua index 3b6507fa..306c0fdb 100644 --- a/src/output/tcpcli.lua +++ b/src/output/tcpcli.lua @@ -33,17 +33,50 @@ local t_name = "output_tcpcli_t" local output_tcpcli_t = ffi.typeof(t_name) local Tcpcli = {} --- Create a new Tcpcli output to send queries to the +-- Create a new Tcpcli output. Optinally connect to the -- .I host -- and --- .IR port . +-- .IR port right away or use +-- .BR connect () +-- later on. function Tcpcli.new(host, port) local self = { obj = output_tcpcli_t(), } - C.output_tcpcli_init(self.obj, host, port) + C.output_tcpcli_init(self.obj) ffi.gc(self.obj, C.output_tcpcli_destroy) - return setmetatable(self, { __index = Tcpcli }) + self = setmetatable(self, { __index = Tcpcli }) + if host and port then + if self:connect(host, port) ~= 0 then + return + end + end + return self +end + +-- Connect to the +-- .I host +-- and +-- .IR port . +function Tcpcli.connect(host, port) + return C.output_tcpcli_connect(self.obj, host, port) +end + +-- Enable (true) or disable (false) nonblocking mode and +-- return 0 if successful, if +-- .I bool +-- is not specified then return if nonblocking mode is on (true) or off (false). +function Tcpcli.nonblocking(bool) + if bool == nil then + if C.output_tcpcli_nonblocking(self.obj) == 1 then + return true + end + return false + elseif bool == true then + return C.output_tcpcli_set_nonblocking(self.obj, 1) + else + return C.output_tcpcli_set_nonblocking(self.obj, 0) + end end -- Return the C functions and context for receiving objects. diff --git a/src/output/udpcli.c b/src/output/udpcli.c index 512ebc5d..43209273 100644 --- a/src/output/udpcli.c +++ b/src/output/udpcli.c @@ -25,19 +25,15 @@ #include "core/object/udp.h" #include "core/object/tcp.h" -#include -#include #include #include #include #include -#include static core_log_t _log = LOG_T_INIT("output.udpcli"); static output_udpcli_t _defaults = { LOG_T_INIT_OBJ("output.udpcli"), - 0, 0, -1, - 0, 0 + 0, 0, -1 }; core_log_t* output_udpcli_log() @@ -45,24 +41,46 @@ core_log_t* output_udpcli_log() return &_log; } -int output_udpcli_init(output_udpcli_t* self, const char* host, const char* port) +int output_udpcli_init(output_udpcli_t* self) { - struct addrinfo* addr; - int err; - - if (!self || !host || !port) { + if (!self) { return 1; } *self = _defaults; - ldebug("init %s %s", host, port); + ldebug("init"); + + return 0; +} - if (!(self->addr = malloc(sizeof(struct sockaddr_storage)))) { - lcritical("malloc"); +int output_udpcli_destroy(output_udpcli_t* self) +{ + if (!self) { return 1; } + ldebug("destroy"); + + if (self->fd > -1) { + shutdown(self->fd, SHUT_RDWR); + close(self->fd); + } + + return 0; +} + +int output_udpcli_connect(output_udpcli_t* self, const char* host, const char* port) +{ + struct addrinfo* addr; + int err; + + if (!self || self->fd > -1 || !host || !port) { + return 1; + } + + ldebug("connect %s %s", host, port); + if ((err = getaddrinfo(host, port, 0, &addr))) { lcritical("getaddrinfo() %d", err); return 1; @@ -78,33 +96,59 @@ int output_udpcli_init(output_udpcli_t* self, const char* host, const char* port addr->ai_protocol, addr->ai_addrlen); - memcpy(self->addr, addr->ai_addr, addr->ai_addrlen); + memcpy(&self->addr, addr->ai_addr, addr->ai_addrlen); self->addr_len = addr->ai_addrlen; freeaddrinfo(addr); - if ((self->fd = socket(((struct sockaddr*)self->addr)->sa_family, SOCK_DGRAM, 0)) < 0) { + if ((self->fd = socket(((struct sockaddr*)&self->addr)->sa_family, SOCK_DGRAM, 0)) < 0) { lcritical("socket failed"); return 1; } - if ((err = fcntl(self->fd, F_GETFL)) == -1 - || fcntl(self->fd, F_SETFL, err | O_NONBLOCK)) { - lcritical("fcntl failed"); + return 0; +} + +int output_udpcli_nonblocking(output_udpcli_t* self) +{ + int flags; + + if (!self || self->fd < 0) { + return -1; + } + + flags = fcntl(self->fd, F_GETFL); + if (flags != -1) { + flags = flags & O_NONBLOCK ? 1 : 0; } - return 0; + return flags; } -int output_udpcli_destroy(output_udpcli_t* self) +int output_udpcli_set_nonblocking(output_udpcli_t* self, int nonblocking) { - if (!self) { + int flags; + + if (!self || self->fd < 0) { return 1; } - ldebug("destroy"); + ldebug("set nonblocking %d", nonblocking); - if (self->fd > -1) { - close(self->fd); + if ((flags = fcntl(self->fd, F_GETFL)) == -1) { + lcritical("fcntl(FL_GETFL) failed"); + return 1; + } + + if (nonblocking) { + if (fcntl(self->fd, F_SETFL, flags | O_NONBLOCK)) { + lcritical("fcntl(FL_SETFL) failed"); + return 1; + } + } else { + if (fcntl(self->fd, F_SETFL, flags & ~O_NONBLOCK)) { + lcritical("fcntl(FL_SETFL) failed"); + return 1; + } } return 0; @@ -144,22 +188,13 @@ static int _receive(void* ctx, const core_object_t* obj) sent = 0; self->pkts++; for (;;) { - ssize_t ret = sendto(self->fd, payload + sent, len - sent, 0, (struct sockaddr*)self->addr, self->addr_len); + ssize_t ret = sendto(self->fd, payload + sent, len - sent, 0, (struct sockaddr*)&self->addr, self->addr_len); if (ret > -1) { sent += ret; if (sent < len) continue; return 0; } - switch (errno) { - case EAGAIN: -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif - continue; - default: - break; - } self->errs++; break; } diff --git a/src/output/udpcli.h b/src/output/udpcli.h index 3283a69f..f6e70563 100644 --- a/src/output/udpcli.h +++ b/src/output/udpcli.h @@ -24,6 +24,9 @@ #ifndef __dnsjit_output_udpcli_h #define __dnsjit_output_udpcli_h +#include +#include + #include "output/udpcli.hh" #endif diff --git a/src/output/udpcli.hh b/src/output/udpcli.hh index 68f1e996..63e2ef79 100644 --- a/src/output/udpcli.hh +++ b/src/output/udpcli.hh @@ -20,19 +20,23 @@ //lua:require("dnsjit.core.log") //lua:require("dnsjit.core.receiver_h") +//lua:require("dnsjit.core.compat_h") typedef struct output_udpcli { core_log_t _log; size_t pkts, errs; int fd; - void* addr; - size_t addr_len; + struct sockaddr_storage addr; + size_t addr_len; } output_udpcli_t; core_log_t* output_udpcli_log(); -int output_udpcli_init(output_udpcli_t* self, const char* host, const char* port); +int output_udpcli_init(output_udpcli_t* self); int output_udpcli_destroy(output_udpcli_t* self); +int output_udpcli_connect(output_udpcli_t* self, const char* host, const char* port); +int output_udpcli_nonblocking(output_udpcli_t* self); +int output_udpcli_set_nonblocking(output_udpcli_t* self, int nonblocking); core_receiver_t output_udpcli_receiver(); diff --git a/src/output/udpcli.lua b/src/output/udpcli.lua index 6527a340..f97038a2 100644 --- a/src/output/udpcli.lua +++ b/src/output/udpcli.lua @@ -33,17 +33,50 @@ local t_name = "output_udpcli_t" local output_udpcli_t = ffi.typeof(t_name) local Udpcli = {} --- Create a new Udpcli output to send queries to the +-- Create a new Udpcli output. Optinally connect to the -- .I host -- and --- .IR port . +-- .IR port right away or use +-- .BR connect () +-- later on. function Udpcli.new(host, port) local self = { obj = output_udpcli_t(), } - C.output_udpcli_init(self.obj, host, port) + C.output_udpcli_init(self.obj) ffi.gc(self.obj, C.output_udpcli_destroy) - return setmetatable(self, { __index = Udpcli }) + self = setmetatable(self, { __index = Udpcli }) + if host and port then + if self:connect(host, port) ~= 0 then + return + end + end + return self +end + +-- Connect to the +-- .I host +-- and +-- .IR port . +function Udpcli.connect(host, port) + return C.output_udpcli_connect(self.obj, host, port) +end + +-- Enable (true) or disable (false) nonblocking mode and +-- return 0 if successful, if +-- .I bool +-- is not specified then return if nonblocking mode is on (true) or off (false). +function Udpcli.nonblocking(bool) + if bool == nil then + if C.output_udpcli_nonblocking(self.obj) == 1 then + return true + end + return false + elseif bool == true then + return C.output_udpcli_set_nonblocking(self.obj, 1) + else + return C.output_udpcli_set_nonblocking(self.obj, 0) + end end -- Return the C functions and context for receiving objects.