Adding upstream version 0.2.0.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
23dbed389d
commit
a84695b834
79 changed files with 7127 additions and 0 deletions
48
examples/Makefile.am
Normal file
48
examples/Makefile.am
Normal file
|
@ -0,0 +1,48 @@
|
|||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
CLEANFILES =
|
||||
|
||||
AM_CFLAGS = -I$(top_srcdir)/src \
|
||||
$(tinyframe_CFLAGS) \
|
||||
$(protobuf_c_CFLAGS)
|
||||
|
||||
AM_LDFLAGS = $(protobuf_c_LIBS) \
|
||||
$(tinyframe_LIBS) -static
|
||||
|
||||
EXTRA_DIST = print_dnstap.c create_dnstap.c
|
||||
|
||||
if BUILD_EXAMPLES
|
||||
|
||||
noinst_PROGRAMS = reader writer sender receiver reader_sender
|
||||
|
||||
reader_SOURCES = reader.c
|
||||
reader_LDADD = ../src/libdnswire.la
|
||||
|
||||
writer_SOURCES = writer.c
|
||||
writer_LDADD = ../src/libdnswire.la
|
||||
|
||||
sender_SOURCES = sender.c
|
||||
sender_LDADD = ../src/libdnswire.la
|
||||
|
||||
receiver_SOURCES = receiver.c
|
||||
receiver_LDADD = ../src/libdnswire.la
|
||||
|
||||
reader_sender_SOURCES = reader_sender.c
|
||||
reader_sender_LDADD = ../src/libdnswire.la
|
||||
|
||||
if HAVE_LIBUV
|
||||
|
||||
AM_CFLAGS += -I$(uv_CFLAGS)
|
||||
AM_LDFLAGS += $(uv_LIBS)
|
||||
|
||||
noinst_PROGRAMS += daemon_sender_uv client_receiver_uv
|
||||
|
||||
daemon_sender_uv_SOURCES = daemon_sender_uv.c
|
||||
daemon_sender_uv_LDADD = ../src/libdnswire.la
|
||||
|
||||
client_receiver_uv_SOURCES = client_receiver_uv.c
|
||||
client_receiver_uv_LDADD = ../src/libdnswire.la
|
||||
|
||||
endif
|
||||
|
||||
endif
|
114
examples/README.md
Normal file
114
examples/README.md
Normal file
|
@ -0,0 +1,114 @@
|
|||
# Examples
|
||||
|
||||
- `reader`: Example of reading DNSTAP from a file and printing it's content, using `dnswire_reader` (unidirectional mode)
|
||||
- `writer`: Example of constructing a DNSTAP message and writing it to a file, using `dnswire_writer` (unidirectional mode)
|
||||
- `receiver`: Example of receiving a DNSTAP message over a TCP connection and printing it's content, using `dnswire_reader` (bidirectional mode)
|
||||
- `sender`: Example of constructing a DNSTAP message and sending it over a TCP connection, using `dnswire_writer` (bidirectional mode)
|
||||
- `daemon_sender_uv`: Example of a daemon that will continuously send DNSTAP messages to connected clients (unidirectional mode), using the event engine `libuv` and `dnstap_encode_protobuf` along with `tinyframe` to encode once and send to many
|
||||
- `client_receiver_uv`: Example of a client that will receive DNSTAP message from the daemon (unidirectional mode), using the event engine `libuv` and `dnswire_reader` with the buffer push interface
|
||||
- `reader_sender`: Example of a reader that read DNSTAP from a file (unidirectional mode) and then sends the DNSTAP messages over a TCP connection (bidirectional mode)
|
||||
|
||||
## receiver and sender
|
||||
|
||||
These examples uses the way of connecting as implemented in the `fstrm`
|
||||
library, the receiver listens for connections by the sender and the sender
|
||||
connects to the receiver.
|
||||
|
||||
```
|
||||
$ ./receiver 127.0.0.1 5353
|
||||
socket
|
||||
bind
|
||||
listen
|
||||
accept
|
||||
receiving...
|
||||
---- dnstap
|
||||
identity: sender
|
||||
version: 0.1.0
|
||||
message:
|
||||
type: MESSAGE
|
||||
query_time: 1574765731.199945162
|
||||
response_time: 1574765731.199945362
|
||||
socket_family: INET
|
||||
socket_protocol: UDP
|
||||
query_address: 127.0.0.1
|
||||
query_port: 12345
|
||||
response_address: 127.0.0.1
|
||||
response_port: 53
|
||||
query_message_length: 27
|
||||
query_message: dns_wire_format_placeholder
|
||||
response_message_length: 27
|
||||
response_message: dns_wire_format_placeholder
|
||||
----
|
||||
stopped
|
||||
```
|
||||
|
||||
```
|
||||
$ ./sender 127.0.0.1 5353
|
||||
socket
|
||||
connect
|
||||
sending...
|
||||
sent, stopping...
|
||||
stopped
|
||||
```
|
||||
|
||||
## daemon_sender_uv and client_receiver_uv
|
||||
|
||||
These examples works in the reverse way compared to `receiver` and `sender`,
|
||||
and maybe a more traditional way, the daemon listens and accepts connections
|
||||
from new clients, and will continuously send messages to established clients
|
||||
that are ready to receive them.
|
||||
|
||||
```
|
||||
$ ./daemon_sender_uv 127.0.0.1 5353
|
||||
client 1 connected
|
||||
client 1: sending control start and content type
|
||||
client 1: sending DNSTAP
|
||||
client 1: sending DNSTAP
|
||||
client 1 disconnected
|
||||
```
|
||||
|
||||
```
|
||||
$ ./client_receiver_uv 127.0.0.1 5353
|
||||
received 42 bytes
|
||||
got control start
|
||||
got content type DNSTAP
|
||||
received 133 bytes
|
||||
---- dnstap
|
||||
identity: daemon_sender_uv
|
||||
version: 0.1.0
|
||||
message:
|
||||
type: MESSAGE
|
||||
query_time: 1574257180.95619354
|
||||
response_time: 1574257180.95619490
|
||||
socket_family: INET
|
||||
socket_protocol: UDP
|
||||
query_address: 127.0.0.1
|
||||
query_port: 12345
|
||||
response_address: 127.0.0.1
|
||||
response_port: 53
|
||||
query_message_length: 27
|
||||
query_message: dns_wire_format_placeholder
|
||||
response_message_length: 27
|
||||
response_message: dns_wire_format_placeholder
|
||||
----
|
||||
received 133 bytes
|
||||
---- dnstap
|
||||
identity: daemon_sender_uv
|
||||
version: 0.1.0
|
||||
message:
|
||||
type: MESSAGE
|
||||
query_time: 1574257181.96381443
|
||||
response_time: 1574257181.96381557
|
||||
socket_family: INET
|
||||
socket_protocol: UDP
|
||||
query_address: 127.0.0.1
|
||||
query_port: 12345
|
||||
response_address: 127.0.0.1
|
||||
response_port: 53
|
||||
query_message_length: 27
|
||||
query_message: dns_wire_format_placeholder
|
||||
response_message_length: 27
|
||||
response_message: dns_wire_format_placeholder
|
||||
----
|
||||
^C
|
||||
```
|
134
examples/client_receiver_uv.c
Normal file
134
examples/client_receiver_uv.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
#include <dnswire/reader.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <uv.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "print_dnstap.c"
|
||||
|
||||
#define BUF_SIZE 4096
|
||||
|
||||
uv_loop_t* loop;
|
||||
uv_tcp_t sock;
|
||||
uv_connect_t conn;
|
||||
char rbuf[BUF_SIZE];
|
||||
|
||||
struct dnswire_reader reader;
|
||||
|
||||
void client_alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
|
||||
{
|
||||
buf->base = rbuf;
|
||||
buf->len = sizeof(rbuf);
|
||||
}
|
||||
|
||||
void client_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf)
|
||||
{
|
||||
if (nread > 0) {
|
||||
/*
|
||||
* We now push all the data we got to the reader.
|
||||
*/
|
||||
size_t pushed = 0;
|
||||
|
||||
while (pushed < nread) {
|
||||
enum dnswire_result res = dnswire_reader_push(&reader, (uint8_t*)&buf->base[pushed], nread - pushed, 0, 0);
|
||||
|
||||
pushed += dnswire_reader_pushed(reader);
|
||||
|
||||
switch (res) {
|
||||
case dnswire_have_dnstap:
|
||||
/*
|
||||
* We got a DNSTAP message, lets print it!
|
||||
*/
|
||||
print_dnstap(dnswire_reader_dnstap(reader));
|
||||
break;
|
||||
case dnswire_again:
|
||||
case dnswire_need_more:
|
||||
break;
|
||||
case dnswire_endofdata:
|
||||
/*
|
||||
* The remote end sent a control stop or finish.
|
||||
*/
|
||||
uv_close((uv_handle_t*)handle, 0);
|
||||
return;
|
||||
default:
|
||||
fprintf(stderr, "dnswire_reader_fread() error\n");
|
||||
uv_close((uv_handle_t*)handle, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nread < 0) {
|
||||
if (nread != UV_EOF) {
|
||||
fprintf(stderr, "client_read() error: %s\n", uv_err_name(nread));
|
||||
} else {
|
||||
printf("disconnected\n");
|
||||
}
|
||||
uv_close((uv_handle_t*)handle, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void on_connect(uv_connect_t* req, int status)
|
||||
{
|
||||
/*
|
||||
* We have connected to the sender, check that there was no errors
|
||||
* and start receiving incoming frames.
|
||||
*/
|
||||
|
||||
if (status < 0) {
|
||||
fprintf(stderr, "on_connect() error: %s\n", uv_strerror(status));
|
||||
return;
|
||||
}
|
||||
|
||||
uv_read_start((uv_stream_t*)&sock, client_alloc_buffer, client_read);
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "usage: client_receiver_uv <IP> <port>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We first initialize the reader and check that it can allocate the
|
||||
* buffers it needs.
|
||||
*/
|
||||
|
||||
if (dnswire_reader_init(&reader) != dnswire_ok) {
|
||||
fprintf(stderr, "Unable to initialize dnswire reader\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We set this reader to reject bidirectional communication.
|
||||
*/
|
||||
if (dnswire_reader_allow_bidirectional(&reader, false) != dnswire_ok) {
|
||||
fprintf(stderr, "Unable to deny bidirectional communication\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We setup a TCP client using libuv and connect to the given server.
|
||||
*/
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
int port = atoi(argv[2]);
|
||||
|
||||
if (strchr(argv[1], ':')) {
|
||||
uv_ip6_addr(argv[1], port, (struct sockaddr_in6*)&addr);
|
||||
} else {
|
||||
uv_ip4_addr(argv[1], port, (struct sockaddr_in*)&addr);
|
||||
}
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
uv_tcp_init(loop, &sock);
|
||||
uv_tcp_connect(&conn, &sock, (const struct sockaddr*)&addr, on_connect);
|
||||
|
||||
return uv_run(loop, UV_RUN_DEFAULT);
|
||||
}
|
99
examples/create_dnstap.c
Normal file
99
examples/create_dnstap.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
#include <dnswire/version.h>
|
||||
#include <dnswire/dnstap.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
static char dns_wire_format_placeholder[] = "dns_wire_format_placeholder";
|
||||
|
||||
static inline struct dnstap create_dnstap(const char* identity)
|
||||
{
|
||||
/*
|
||||
* Now we initialize a DNSTAP message.
|
||||
*/
|
||||
|
||||
struct dnstap d = DNSTAP_INITIALIZER;
|
||||
|
||||
/*
|
||||
* DNSTAP has a header with information about who constructed the
|
||||
* message.
|
||||
*/
|
||||
|
||||
dnstap_set_identity_string(d, identity);
|
||||
dnstap_set_version_string(d, DNSWIRE_VERSION_STRING);
|
||||
|
||||
/*
|
||||
* Now we specify that this is a DNSTAP message, this is the one that
|
||||
* holds the DNS.
|
||||
*/
|
||||
|
||||
dnstap_set_type(d, DNSTAP_TYPE_MESSAGE);
|
||||
|
||||
/*
|
||||
* The message can have different types, we specify this is a query
|
||||
* made by a tool.
|
||||
*/
|
||||
|
||||
dnstap_message_set_type(d, DNSTAP_MESSAGE_TYPE_TOOL_QUERY);
|
||||
|
||||
/*
|
||||
* As most DNS comes over the network we can specify over what protocol,
|
||||
* where from, to whom it came to and when it happened.
|
||||
*
|
||||
* Even if all fields are optional and there is no restriction on how
|
||||
* many or how few you set, there is a recommended way of filling in
|
||||
* the messages based on the message type.
|
||||
*
|
||||
* Please see the description of this at the bottom of
|
||||
* `src/dnstap.pb/dnstap.proto` or
|
||||
* <https://github.com/dnstap/dnstap.pb/blob/master/dnstap.proto>.
|
||||
*/
|
||||
|
||||
dnstap_message_set_socket_family(d, DNSTAP_SOCKET_FAMILY_INET);
|
||||
dnstap_message_set_socket_protocol(d, DNSTAP_SOCKET_PROTOCOL_UDP);
|
||||
|
||||
unsigned char query_address[sizeof(struct in_addr)];
|
||||
if (inet_pton(AF_INET, "127.0.0.1", query_address) != 1) {
|
||||
fprintf(stderr, "inet_pton(127.0.0.1) failed: %s\n", strerror(errno));
|
||||
} else {
|
||||
dnstap_message_set_query_address(d, query_address, sizeof(query_address));
|
||||
}
|
||||
dnstap_message_set_query_port(d, 12345);
|
||||
|
||||
struct timespec query_time = { 0, 0 };
|
||||
clock_gettime(CLOCK_REALTIME, &query_time);
|
||||
dnstap_message_set_query_time_sec(d, query_time.tv_sec);
|
||||
dnstap_message_set_query_time_nsec(d, query_time.tv_nsec);
|
||||
|
||||
unsigned char response_address[sizeof(struct in_addr)];
|
||||
if (inet_pton(AF_INET, "127.0.0.1", response_address) != 1) {
|
||||
fprintf(stderr, "inet_pton(127.0.0.1) failed: %s\n", strerror(errno));
|
||||
} else {
|
||||
dnstap_message_set_response_address(d, response_address, sizeof(response_address));
|
||||
}
|
||||
dnstap_message_set_response_port(d, 53);
|
||||
|
||||
struct timespec response_time = { 0, 0 };
|
||||
clock_gettime(CLOCK_REALTIME, &response_time);
|
||||
dnstap_message_set_response_time_sec(d, response_time.tv_sec);
|
||||
dnstap_message_set_response_time_nsec(d, response_time.tv_nsec);
|
||||
|
||||
/*
|
||||
* If we also had the DNS wire format we could use it, now we fill it
|
||||
* with a placeholder text.
|
||||
*
|
||||
* NOTE: This will be invalid DNS if the output file is used with a
|
||||
* tool that uses the DNS messages.
|
||||
*/
|
||||
|
||||
dnstap_message_set_query_message(d, dns_wire_format_placeholder, sizeof(dns_wire_format_placeholder) - 1);
|
||||
|
||||
dnstap_message_set_response_message(d, dns_wire_format_placeholder, sizeof(dns_wire_format_placeholder) - 1);
|
||||
|
||||
return d;
|
||||
}
|
254
examples/daemon_sender_uv.c
Normal file
254
examples/daemon_sender_uv.c
Normal file
|
@ -0,0 +1,254 @@
|
|||
#include <tinyframe/tinyframe.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <uv.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "create_dnstap.c"
|
||||
|
||||
#define BUF_SIZE 4096
|
||||
|
||||
enum client_state {
|
||||
no_state,
|
||||
writing_start,
|
||||
started,
|
||||
writing_frame,
|
||||
};
|
||||
|
||||
struct client;
|
||||
struct client {
|
||||
struct client* next;
|
||||
size_t id;
|
||||
enum client_state state;
|
||||
uv_tcp_t conn;
|
||||
char rbuf[BUF_SIZE];
|
||||
uv_write_t wreq;
|
||||
uv_buf_t wbuf;
|
||||
uint8_t buf[BUF_SIZE];
|
||||
};
|
||||
|
||||
struct client* clients = 0;
|
||||
size_t client_id = 1;
|
||||
|
||||
static char content_type[] = "protobuf:dnstap.Dnstap";
|
||||
|
||||
uv_loop_t* loop;
|
||||
|
||||
struct client* client_new()
|
||||
{
|
||||
struct client* c = malloc(sizeof(struct client));
|
||||
if (c) {
|
||||
c->conn.data = c;
|
||||
c->next = clients;
|
||||
c->id = client_id++;
|
||||
c->state = no_state;
|
||||
c->wbuf.base = (void*)c->buf;
|
||||
clients = c;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void client_close(uv_handle_t* handle)
|
||||
{
|
||||
struct client* c = handle->data;
|
||||
|
||||
if (clients == c) {
|
||||
clients = c->next;
|
||||
} else {
|
||||
struct client* prev = clients;
|
||||
|
||||
while (prev) {
|
||||
if (prev->next == c) {
|
||||
prev->next = c->next;
|
||||
break;
|
||||
}
|
||||
prev = prev->next;
|
||||
}
|
||||
}
|
||||
|
||||
free(c);
|
||||
}
|
||||
|
||||
void client_alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
|
||||
{
|
||||
buf->base = ((struct client*)handle->data)->rbuf;
|
||||
buf->len = BUF_SIZE;
|
||||
}
|
||||
|
||||
void client_read(uv_stream_t* client, ssize_t nread, const uv_buf_t* buf)
|
||||
{
|
||||
/*
|
||||
* We discard any input from the client and only check for errors or
|
||||
* if the connection was closed.
|
||||
*/
|
||||
|
||||
if (nread < 0) {
|
||||
if (nread != UV_EOF) {
|
||||
fprintf(stderr, "client_read() error: %s\n", uv_err_name(nread));
|
||||
} else {
|
||||
printf("client %zu disconnected\n", ((struct client*)client->data)->id);
|
||||
}
|
||||
uv_close((uv_handle_t*)client, client_close);
|
||||
}
|
||||
}
|
||||
|
||||
void client_write(uv_write_t* req, int status)
|
||||
{
|
||||
/*
|
||||
* After a write we check that there was no errors and then set the
|
||||
* client in a state that allows `tick()` to send DNSTAP messages to it.
|
||||
*/
|
||||
|
||||
if (status) {
|
||||
fprintf(stderr, "client_write() error: %s\n", uv_strerror(status));
|
||||
uv_close((uv_handle_t*)req->handle, client_close);
|
||||
return;
|
||||
}
|
||||
|
||||
((struct client*)req->handle->data)->state = started;
|
||||
}
|
||||
|
||||
void on_new_connection(uv_stream_t* server, int status)
|
||||
{
|
||||
if (status < 0) {
|
||||
fprintf(stderr, "on_new_connection() error: %s\n", uv_strerror(status));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a new client connecting, create a client struct to hold the
|
||||
* connection, accept it and send the control start frame.
|
||||
*/
|
||||
|
||||
struct client* client = client_new();
|
||||
if (!client) {
|
||||
fprintf(stderr, "on_new_connection() out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uv_tcp_init(loop, &client->conn);
|
||||
if (uv_accept(server, (uv_stream_t*)&client->conn) == 0) {
|
||||
printf("client %zu connected\n", client->id);
|
||||
|
||||
uv_read_start((uv_stream_t*)&client->conn, client_alloc_buffer, client_read);
|
||||
|
||||
struct tinyframe_writer writer = TINYFRAME_WRITER_INITIALIZER;
|
||||
|
||||
/*
|
||||
* First we write, to the buffer, a control start with a content type
|
||||
* control field for the DNSTAP protobuf content type.
|
||||
*
|
||||
* Then we send it.
|
||||
*/
|
||||
|
||||
if (tinyframe_write_control_start(&writer, client->buf, BUF_SIZE, content_type, sizeof(content_type) - 1) != tinyframe_ok) {
|
||||
fprintf(stderr, "tinyframe_write_control_start() failed\n");
|
||||
uv_close((uv_handle_t*)&client->conn, client_close);
|
||||
return;
|
||||
}
|
||||
printf("client %zu: sending control start and content type\n", client->id);
|
||||
|
||||
client->wbuf.len = writer.bytes_wrote;
|
||||
uv_write((uv_write_t*)&client->wreq, (uv_stream_t*)&client->conn, &client->wbuf, 1, client_write);
|
||||
client->state = writing_start;
|
||||
} else {
|
||||
uv_close((uv_handle_t*)&client->conn, client_close);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called every second and will create a DNSTAP message
|
||||
* and send it to all available clients.
|
||||
*/
|
||||
|
||||
void tick(uv_timer_t* handle)
|
||||
{
|
||||
/*
|
||||
* Now we create a DNSTAP message.
|
||||
*/
|
||||
|
||||
struct dnstap d = create_dnstap("daemon_sender_uv");
|
||||
|
||||
/*
|
||||
* Now that the message is prepared we can begin encapsulating it in
|
||||
* protobuf and Frame Streams.
|
||||
*
|
||||
* First we ask what the encoded size of the protobuf message would be
|
||||
* and then we allocate a buffer with of that size plus the size of
|
||||
* a Frame Streams frame header.
|
||||
*
|
||||
* Then we encode the DNSTAP message and put it after the frame header
|
||||
* and call `tinyframe_set_header()` to set the header.
|
||||
*/
|
||||
|
||||
size_t frame_len = dnstap_encode_protobuf_size(&d);
|
||||
uint8_t frame[TINYFRAME_HEADER_SIZE + frame_len];
|
||||
dnstap_encode_protobuf(&d, &frame[TINYFRAME_HEADER_SIZE]);
|
||||
tinyframe_set_header(frame, frame_len);
|
||||
|
||||
if (sizeof(frame) > BUF_SIZE) {
|
||||
fprintf(stderr, "frame larger the client's buffers\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* We now loop over all the connected clients and send the message
|
||||
* to those that are currently not busy.
|
||||
*/
|
||||
|
||||
struct client* c = clients;
|
||||
while (c) {
|
||||
if (c->state == started) {
|
||||
c->wbuf.len = sizeof(frame);
|
||||
memcpy(c->buf, frame, sizeof(frame));
|
||||
uv_write((uv_write_t*)&c->wreq, (uv_stream_t*)&c->conn, &c->wbuf, 1, client_write);
|
||||
c->state = writing_frame;
|
||||
|
||||
printf("client %zu: sending DNSTAP\n", c->id);
|
||||
}
|
||||
c = c->next;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "usage: daemon_sender_uv <IP> <port>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We setup a TCP server using libuv and listen for connections,
|
||||
* along with a timer that calls the function to send DNSTAP messages
|
||||
* to all clients.
|
||||
*/
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
int port = atoi(argv[2]);
|
||||
|
||||
if (strchr(argv[1], ':')) {
|
||||
uv_ip6_addr(argv[1], port, (struct sockaddr_in6*)&addr);
|
||||
} else {
|
||||
uv_ip4_addr(argv[1], port, (struct sockaddr_in*)&addr);
|
||||
}
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
uv_tcp_t server;
|
||||
uv_tcp_init(loop, &server);
|
||||
uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);
|
||||
int r = uv_listen((uv_stream_t*)&server, 128, on_new_connection);
|
||||
if (r) {
|
||||
fprintf(stderr, "uv_listen() failed: %s\n", uv_strerror(r));
|
||||
return 1;
|
||||
}
|
||||
|
||||
uv_timer_t ticker;
|
||||
uv_timer_init(loop, &ticker);
|
||||
uv_timer_start(&ticker, tick, 1000, 1000);
|
||||
|
||||
return uv_run(loop, UV_RUN_DEFAULT);
|
||||
}
|
122
examples/print_dnstap.c
Normal file
122
examples/print_dnstap.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
#include <dnswire/dnstap.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
static const char* printable_string(const uint8_t* data, size_t len)
|
||||
{
|
||||
static char buf[512], hex;
|
||||
size_t r = 0, w = 0;
|
||||
|
||||
while (r < len && w < sizeof(buf) - 1) {
|
||||
if (isprint(data[r])) {
|
||||
buf[w++] = data[r++];
|
||||
} else {
|
||||
if (w + 4 >= sizeof(buf) - 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
buf[w++] = '\\';
|
||||
buf[w++] = 'x';
|
||||
hex = (data[r] & 0xf0) >> 4;
|
||||
if (hex > 9) {
|
||||
buf[w++] = 'a' + (hex - 10);
|
||||
} else {
|
||||
buf[w++] = '0' + hex;
|
||||
}
|
||||
hex = data[r++] & 0xf;
|
||||
if (hex > 9) {
|
||||
buf[w++] = 'a' + (hex - 10);
|
||||
} else {
|
||||
buf[w++] = '0' + hex;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (w >= sizeof(buf)) {
|
||||
buf[sizeof(buf) - 1] = 0;
|
||||
} else {
|
||||
buf[w] = 0;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static const char* printable_ip_address(const uint8_t* data, size_t len)
|
||||
{
|
||||
static char buf[INET6_ADDRSTRLEN];
|
||||
|
||||
buf[0] = 0;
|
||||
if (len == 4) {
|
||||
inet_ntop(AF_INET, data, buf, sizeof(buf));
|
||||
} else if (len == 16) {
|
||||
inet_ntop(AF_INET6, data, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void print_dnstap(const struct dnstap* d)
|
||||
{
|
||||
printf("---- dnstap\n");
|
||||
|
||||
/*
|
||||
* Now we can print the available information in the message.
|
||||
*/
|
||||
|
||||
if (dnstap_has_identity(*d)) {
|
||||
printf("identity: %s\n", printable_string(dnstap_identity(*d), dnstap_identity_length(*d)));
|
||||
}
|
||||
if (dnstap_has_version(*d)) {
|
||||
printf("version: %s\n", printable_string(dnstap_version(*d), dnstap_version_length(*d)));
|
||||
}
|
||||
if (dnstap_has_extra(*d)) {
|
||||
printf("extra: %s\n", printable_string(dnstap_extra(*d), dnstap_extra_length(*d)));
|
||||
}
|
||||
|
||||
if (dnstap_type(*d) == DNSTAP_TYPE_MESSAGE && dnstap_has_message(*d)) {
|
||||
printf("message:\n type: %s\n", DNSTAP_MESSAGE_TYPE_STRING[dnstap_message_type(*d)]);
|
||||
|
||||
if (dnstap_message_has_query_time_sec(*d) && dnstap_message_has_query_time_nsec(*d)) {
|
||||
printf(" query_time: %" PRIu64 ".%" PRIu32 "\n", dnstap_message_query_time_sec(*d), dnstap_message_query_time_nsec(*d));
|
||||
}
|
||||
if (dnstap_message_has_response_time_sec(*d) && dnstap_message_has_response_time_nsec(*d)) {
|
||||
printf(" response_time: %" PRIu64 ".%" PRIu32 "\n", dnstap_message_response_time_sec(*d), dnstap_message_response_time_nsec(*d));
|
||||
}
|
||||
if (dnstap_message_has_socket_family(*d)) {
|
||||
printf(" socket_family: %s\n", DNSTAP_SOCKET_FAMILY_STRING[dnstap_message_socket_family(*d)]);
|
||||
}
|
||||
if (dnstap_message_has_socket_protocol(*d)) {
|
||||
printf(" socket_protocol: %s\n", DNSTAP_SOCKET_PROTOCOL_STRING[dnstap_message_socket_protocol(*d)]);
|
||||
}
|
||||
if (dnstap_message_has_query_address(*d)) {
|
||||
printf(" query_address: %s\n", printable_ip_address(dnstap_message_query_address(*d), dnstap_message_query_address_length(*d)));
|
||||
}
|
||||
if (dnstap_message_has_query_port(*d)) {
|
||||
printf(" query_port: %u\n", dnstap_message_query_port(*d));
|
||||
}
|
||||
if (dnstap_message_has_response_address(*d)) {
|
||||
printf(" response_address: %s\n", printable_ip_address(dnstap_message_response_address(*d), dnstap_message_response_address_length(*d)));
|
||||
}
|
||||
if (dnstap_message_has_response_port(*d)) {
|
||||
printf(" response_port: %u\n", dnstap_message_response_port(*d));
|
||||
}
|
||||
if (dnstap_message_has_query_zone(*d)) {
|
||||
printf(" query_zone: %s\n", printable_string(dnstap_message_query_zone(*d), dnstap_message_query_zone_length(*d)));
|
||||
}
|
||||
if (dnstap_message_has_query_message(*d)) {
|
||||
printf(" query_message_length: %lu\n", dnstap_message_query_message_length(*d));
|
||||
printf(" query_message: %s\n", printable_string(dnstap_message_query_message(*d), dnstap_message_query_message_length(*d)));
|
||||
}
|
||||
if (dnstap_message_has_response_message(*d)) {
|
||||
printf(" response_message_length: %lu\n", dnstap_message_response_message_length(*d));
|
||||
printf(" response_message: %s\n", printable_string(dnstap_message_response_message(*d), dnstap_message_response_message_length(*d)));
|
||||
}
|
||||
}
|
||||
|
||||
printf("----\n");
|
||||
}
|
65
examples/reader.c
Normal file
65
examples/reader.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
#include <dnswire/reader.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "print_dnstap.c"
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: reader <file>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* First we open the given file and read all of the content.
|
||||
*/
|
||||
|
||||
FILE* fp = fopen(argv[1], "r");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We now initialize the reader and check that it can allocate the
|
||||
* buffers it needs.
|
||||
*/
|
||||
|
||||
struct dnswire_reader reader;
|
||||
int done = 0;
|
||||
|
||||
if (dnswire_reader_init(&reader) != dnswire_ok) {
|
||||
fprintf(stderr, "Unable to initialize dnswire reader\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We now loop until we have a DNSTAP message, the stream was stopped
|
||||
* or we got an error.
|
||||
*/
|
||||
|
||||
while (!done) {
|
||||
switch (dnswire_reader_fread(&reader, fp)) {
|
||||
case dnswire_have_dnstap:
|
||||
print_dnstap(dnswire_reader_dnstap(reader));
|
||||
break;
|
||||
case dnswire_again:
|
||||
case dnswire_need_more:
|
||||
break;
|
||||
case dnswire_endofdata:
|
||||
done = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "dnswire_reader_fread() error\n");
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
dnswire_reader_destroy(reader);
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
225
examples/reader_sender.c
Normal file
225
examples/reader_sender.c
Normal file
|
@ -0,0 +1,225 @@
|
|||
#include <dnswire/reader.h>
|
||||
#include <dnswire/writer.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
/*
|
||||
* This is a combination of reader and simpler_sender, comments may
|
||||
* be a bit off since they haven't been updated for this.
|
||||
*/
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "usage: reader_sender <file> [ <IP> <port> | <unix socket path> ]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* First we open the given file and read all of the content.
|
||||
*/
|
||||
|
||||
FILE* fp = fopen(argv[1], "r");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We now initialize the reader and check that it can allocate the
|
||||
* buffers it needs.
|
||||
*/
|
||||
|
||||
struct dnswire_reader reader;
|
||||
int done = 0;
|
||||
|
||||
if (dnswire_reader_init(&reader) != dnswire_ok) {
|
||||
fprintf(stderr, "Unable to initialize dnswire reader\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We first initialize the writer and check that it can allocate the
|
||||
* buffers it needs.
|
||||
*/
|
||||
|
||||
struct dnswire_writer writer;
|
||||
|
||||
if (dnswire_writer_init(&writer) != dnswire_ok) {
|
||||
fprintf(stderr, "Unable to initialize dnswire writer\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use bidirectional communication over the TCP or UNIX socket.
|
||||
*/
|
||||
if (dnswire_writer_set_bidirectional(&writer, true) != dnswire_ok) {
|
||||
fprintf(stderr, "Unable to set dnswire writer to bidirectional mode\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sockfd;
|
||||
|
||||
if (argc == 3) {
|
||||
/*
|
||||
* We setup and connect to a unix socket at the given path on command line.
|
||||
*/
|
||||
|
||||
struct sockaddr_un path;
|
||||
|
||||
memset(&path, 0, sizeof(struct sockaddr_un));
|
||||
path.sun_family = AF_UNIX;
|
||||
strncpy(path.sun_path, argv[2], sizeof(path.sun_path) - 1);
|
||||
|
||||
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sockfd == -1) {
|
||||
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
printf("socket\n");
|
||||
|
||||
if (connect(sockfd, (struct sockaddr*)&path, sizeof(struct sockaddr_un))) {
|
||||
fprintf(stderr, "connect() failed: %s\n", strerror(errno));
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
printf("connect\n");
|
||||
} else {
|
||||
/*
|
||||
* We setup and connect to the IP and port given on command line.
|
||||
*/
|
||||
|
||||
struct sockaddr_storage addr_store;
|
||||
struct sockaddr_in* addr = (struct sockaddr_in*)&addr_store;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (strchr(argv[2], ':')) {
|
||||
addr->sin_family = AF_INET6;
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
} else {
|
||||
addr->sin_family = AF_INET;
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
}
|
||||
|
||||
if (inet_pton(addr->sin_family, argv[2], &addr->sin_addr) != 1) {
|
||||
fprintf(stderr, "inet_pton(%s) failed: %s\n", argv[2], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
addr->sin_port = ntohs(atoi(argv[3]));
|
||||
|
||||
sockfd = socket(addr->sin_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sockfd == -1) {
|
||||
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
printf("socket\n");
|
||||
|
||||
if (connect(sockfd, (struct sockaddr*)addr, addrlen)) {
|
||||
fprintf(stderr, "connect() failed: %s\n", strerror(errno));
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
printf("connect\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* We now loop until we have a DNSTAP message, the stream was stopped
|
||||
* or we got an error.
|
||||
*/
|
||||
|
||||
int done2 = 0;
|
||||
|
||||
while (!done) {
|
||||
switch (dnswire_reader_fread(&reader, fp)) {
|
||||
case dnswire_have_dnstap:
|
||||
dnswire_writer_set_dnstap(writer, dnswire_reader_dnstap(reader));
|
||||
|
||||
printf("sending...\n");
|
||||
done2 = 0;
|
||||
while (!done2) {
|
||||
switch (dnswire_writer_write(&writer, sockfd)) {
|
||||
case dnswire_ok:
|
||||
/*
|
||||
* The DNSTAP message was written successfully, we can now set
|
||||
* a new DNSTAP message for the writer or stop the stream.
|
||||
*/
|
||||
printf("sent\n");
|
||||
done2 = 1;
|
||||
break;
|
||||
case dnswire_again:
|
||||
break;
|
||||
case dnswire_endofdata:
|
||||
/*
|
||||
* The stream is stopped...
|
||||
*/
|
||||
printf("prematurely stopped\n");
|
||||
done = 1;
|
||||
done2 = 2;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "dnswire_writer_write() error\n");
|
||||
done = 1;
|
||||
done2 = 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case dnswire_again:
|
||||
case dnswire_need_more:
|
||||
break;
|
||||
case dnswire_endofdata:
|
||||
done = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "dnswire_reader_fread() error\n");
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (done != 2) {
|
||||
/*
|
||||
* This stops the stream, loop again until it's stopped.
|
||||
*/
|
||||
printf("stopping...\n");
|
||||
dnswire_writer_stop(&writer);
|
||||
done2 = 0;
|
||||
while (!done2) {
|
||||
switch (dnswire_writer_write(&writer, sockfd)) {
|
||||
case dnswire_again:
|
||||
break;
|
||||
case dnswire_endofdata:
|
||||
/*
|
||||
* The stream is stopped, we're done!
|
||||
*/
|
||||
printf("stopped\n");
|
||||
done2 = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "dnswire_writer_write() error\n");
|
||||
done2 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dnswire_writer_destroy(writer);
|
||||
|
||||
/*
|
||||
* Time to exit, let's shutdown and close the sockets.
|
||||
*/
|
||||
|
||||
shutdown(sockfd, SHUT_RDWR);
|
||||
close(sockfd);
|
||||
|
||||
dnswire_reader_destroy(reader);
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
169
examples/receiver.c
Normal file
169
examples/receiver.c
Normal file
|
@ -0,0 +1,169 @@
|
|||
#include <dnswire/reader.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include "print_dnstap.c"
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: receiver [ <IP> <port> | <unix socket path> ]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We first initialize the reader and check that it can allocate the
|
||||
* buffers it needs.
|
||||
*/
|
||||
|
||||
struct dnswire_reader reader;
|
||||
|
||||
if (dnswire_reader_init(&reader) != dnswire_ok) {
|
||||
fprintf(stderr, "Unable to initialize dnswire reader\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow bidirectional communication over the TCP or UNIX socket.
|
||||
*/
|
||||
if (dnswire_reader_allow_bidirectional(&reader, true) != dnswire_ok) {
|
||||
fprintf(stderr, "Unable to set dnswire reader to bidirectional mode\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sockfd;
|
||||
|
||||
if (argc == 2) {
|
||||
/*
|
||||
* We setup a unix socket at the given path on command line.
|
||||
*/
|
||||
|
||||
struct sockaddr_un path;
|
||||
|
||||
memset(&path, 0, sizeof(struct sockaddr_un));
|
||||
path.sun_family = AF_UNIX;
|
||||
strncpy(path.sun_path, argv[1], sizeof(path.sun_path) - 1);
|
||||
|
||||
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sockfd == -1) {
|
||||
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
printf("socket\n");
|
||||
|
||||
if (bind(sockfd, (struct sockaddr*)&path, sizeof(struct sockaddr_un))) {
|
||||
fprintf(stderr, "bind() failed: %s\n", strerror(errno));
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
printf("bind\n");
|
||||
} else {
|
||||
/*
|
||||
* We setup and listen on the IP and port given on command line.
|
||||
*/
|
||||
|
||||
struct sockaddr_storage addr_store;
|
||||
struct sockaddr_in* addr = (struct sockaddr_in*)&addr_store;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (strchr(argv[1], ':')) {
|
||||
addr->sin_family = AF_INET6;
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
} else {
|
||||
addr->sin_family = AF_INET;
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
}
|
||||
|
||||
if (inet_pton(addr->sin_family, argv[1], &addr->sin_addr) != 1) {
|
||||
fprintf(stderr, "inet_pton(%s) failed: %s\n", argv[1], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
addr->sin_port = ntohs(atoi(argv[2]));
|
||||
|
||||
sockfd = socket(addr->sin_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sockfd == -1) {
|
||||
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
printf("socket\n");
|
||||
|
||||
if (bind(sockfd, (struct sockaddr*)addr, addrlen)) {
|
||||
fprintf(stderr, "bind() failed: %s\n", strerror(errno));
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
printf("bind\n");
|
||||
}
|
||||
|
||||
if (listen(sockfd, 1)) {
|
||||
fprintf(stderr, "listen() failed: %s\n", strerror(errno));
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
printf("listen\n");
|
||||
|
||||
int clifd = accept(sockfd, 0, 0);
|
||||
if (clifd < 0) {
|
||||
fprintf(stderr, "accept() failed: %s\n", strerror(errno));
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
printf("accept\n");
|
||||
|
||||
/*
|
||||
* We have accepted connection from the sender!
|
||||
*
|
||||
* We now loop until we have a DNSTAP message, the stream was stopped
|
||||
* or we got an error.
|
||||
*/
|
||||
|
||||
int done = 0;
|
||||
|
||||
printf("receiving...\n");
|
||||
while (!done) {
|
||||
switch (dnswire_reader_read(&reader, clifd)) {
|
||||
case dnswire_have_dnstap:
|
||||
/*
|
||||
* We received a DNSTAP message, let's print it.
|
||||
*/
|
||||
print_dnstap(dnswire_reader_dnstap(reader));
|
||||
break;
|
||||
case dnswire_again:
|
||||
case dnswire_need_more:
|
||||
/*
|
||||
* This indicates that we need to call the reader again as it
|
||||
* will only do one pass in a non-blocking fasion.
|
||||
*/
|
||||
break;
|
||||
case dnswire_endofdata:
|
||||
/*
|
||||
* The stream was stopped from the sender side, we're done!
|
||||
*/
|
||||
printf("stopped\n");
|
||||
done = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "dnswire_reader_read() error\n");
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
dnswire_reader_destroy(reader);
|
||||
|
||||
/*
|
||||
* Time to exit, let's shutdown and close the sockets.
|
||||
*/
|
||||
|
||||
shutdown(clifd, SHUT_RDWR);
|
||||
close(clifd);
|
||||
close(sockfd);
|
||||
|
||||
return 0;
|
||||
}
|
169
examples/sender.c
Normal file
169
examples/sender.c
Normal file
|
@ -0,0 +1,169 @@
|
|||
#include <dnswire/writer.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include "create_dnstap.c"
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: sender [ <IP> <port> | <unix socket path> ]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We first initialize the writer and check that it can allocate the
|
||||
* buffers it needs.
|
||||
*/
|
||||
|
||||
struct dnswire_writer writer;
|
||||
|
||||
if (dnswire_writer_init(&writer) != dnswire_ok) {
|
||||
fprintf(stderr, "Unable to initialize dnswire writer\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use bidirectional communication over the TCP or UNIX socket.
|
||||
*/
|
||||
if (dnswire_writer_set_bidirectional(&writer, true) != dnswire_ok) {
|
||||
fprintf(stderr, "Unable to set dnswire writer to bidirectional mode\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sockfd;
|
||||
|
||||
if (argc == 2) {
|
||||
/*
|
||||
* We setup and connect to a unix socket at the given path on command line.
|
||||
*/
|
||||
|
||||
struct sockaddr_un path;
|
||||
|
||||
memset(&path, 0, sizeof(struct sockaddr_un));
|
||||
path.sun_family = AF_UNIX;
|
||||
strncpy(path.sun_path, argv[1], sizeof(path.sun_path) - 1);
|
||||
|
||||
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sockfd == -1) {
|
||||
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
printf("socket\n");
|
||||
|
||||
if (connect(sockfd, (struct sockaddr*)&path, sizeof(struct sockaddr_un))) {
|
||||
fprintf(stderr, "connect() failed: %s\n", strerror(errno));
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
printf("connect\n");
|
||||
} else {
|
||||
/*
|
||||
* We setup and connect to the IP and port given on command line.
|
||||
*/
|
||||
|
||||
struct sockaddr_storage addr_store;
|
||||
struct sockaddr_in* addr = (struct sockaddr_in*)&addr_store;
|
||||
socklen_t addrlen;
|
||||
|
||||
if (strchr(argv[1], ':')) {
|
||||
addr->sin_family = AF_INET6;
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
} else {
|
||||
addr->sin_family = AF_INET;
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
}
|
||||
|
||||
if (inet_pton(addr->sin_family, argv[1], &addr->sin_addr) != 1) {
|
||||
fprintf(stderr, "inet_pton(%s) failed: %s\n", argv[1], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
addr->sin_port = ntohs(atoi(argv[2]));
|
||||
|
||||
sockfd = socket(addr->sin_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sockfd == -1) {
|
||||
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
printf("socket\n");
|
||||
|
||||
if (connect(sockfd, (struct sockaddr*)addr, addrlen)) {
|
||||
fprintf(stderr, "connect() failed: %s\n", strerror(errno));
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
printf("connect\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* We are now connected!
|
||||
*
|
||||
* Now we create a DNSTAP message.
|
||||
*/
|
||||
|
||||
struct dnstap d = create_dnstap("sender");
|
||||
|
||||
/*
|
||||
* We set the DNSTAP message the writer should write.
|
||||
*/
|
||||
|
||||
dnswire_writer_set_dnstap(writer, &d);
|
||||
|
||||
/*
|
||||
* We now loop and wait for the DNSTAP message to be written.
|
||||
*/
|
||||
|
||||
int done = 0;
|
||||
|
||||
printf("sending...\n");
|
||||
while (!done) {
|
||||
switch (dnswire_writer_write(&writer, sockfd)) {
|
||||
case dnswire_ok:
|
||||
/*
|
||||
* The DNSTAP message was written successfully, we can now set
|
||||
* a new DNSTAP message for the writer or stop the stream.
|
||||
*
|
||||
* This stops the stream, loop again until it's stopped.
|
||||
*/
|
||||
if (dnswire_writer_stop(&writer) != dnswire_ok) {
|
||||
printf("stopping failed!\n");
|
||||
done = 1;
|
||||
}
|
||||
break;
|
||||
case dnswire_again:
|
||||
/*
|
||||
* This indicates that we need to call the writer again as it
|
||||
* will only do one pass in a non-blocking fasion.
|
||||
*/
|
||||
break;
|
||||
case dnswire_endofdata:
|
||||
/*
|
||||
* The stream is stopped, we're done!
|
||||
*/
|
||||
printf("stopped\n");
|
||||
done = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "dnswire_writer_write() error\n");
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
dnswire_writer_destroy(writer);
|
||||
|
||||
/*
|
||||
* Time to exit, let's shutdown and close the sockets.
|
||||
*/
|
||||
|
||||
shutdown(sockfd, SHUT_RDWR);
|
||||
close(sockfd);
|
||||
|
||||
return 0;
|
||||
}
|
84
examples/writer.c
Normal file
84
examples/writer.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
#include <dnswire/writer.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "create_dnstap.c"
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: writer <file>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We start by opening the output file for writing.
|
||||
*/
|
||||
|
||||
FILE* fp = fopen(argv[1], "w");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We first initialize the writer and check that it can allocate the
|
||||
* buffers it needs.
|
||||
*/
|
||||
|
||||
struct dnswire_writer writer;
|
||||
|
||||
if (dnswire_writer_init(&writer) != dnswire_ok) {
|
||||
fprintf(stderr, "Unable to initialize dnswire writer\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we create a DNSTAP message.
|
||||
*/
|
||||
|
||||
struct dnstap d = create_dnstap("writer");
|
||||
|
||||
/*
|
||||
* We set the DNSTAP message the writer should write.
|
||||
*/
|
||||
|
||||
dnswire_writer_set_dnstap(writer, &d);
|
||||
|
||||
/*
|
||||
* We now loop and wait for the DNSTAP message to be written.
|
||||
*/
|
||||
|
||||
int done = 0;
|
||||
|
||||
while (!done) {
|
||||
switch (dnswire_writer_fwrite(&writer, fp)) {
|
||||
case dnswire_ok:
|
||||
/*
|
||||
* The DNSTAP message was written successfully, we can now set
|
||||
* a new DNSTAP message for the writer or stop the stream.
|
||||
*
|
||||
* This stops the stream, loop again until it's stopped.
|
||||
*/
|
||||
dnswire_writer_stop(&writer);
|
||||
break;
|
||||
case dnswire_again:
|
||||
break;
|
||||
case dnswire_endofdata:
|
||||
/*
|
||||
* The stream is stopped, we're done!
|
||||
*/
|
||||
done = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "dnswire_writer_fwrite() error\n");
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
dnswire_writer_destroy(writer);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue