Browse Source

Initial commit

master
Jeroen Vreeken 6 years ago
commit
862f5d9d05
33 changed files with 4301 additions and 0 deletions
  1. +8
    -0
      .gitignore
  2. +50
    -0
      Makefile
  3. +98
    -0
      build.mk
  4. +29
    -0
      dml.h
  5. +126
    -0
      dml_client.c
  6. +27
    -0
      dml_client.h
  7. +97
    -0
      dml_config.c
  8. +27
    -0
      dml_config.h
  9. +207
    -0
      dml_connection.c
  10. +39
    -0
      dml_connection.h
  11. +307
    -0
      dml_crypto.c
  12. +47
    -0
      dml_crypto.h
  13. +106
    -0
      dml_id.c
  14. +30
    -0
      dml_id.h
  15. +148
    -0
      dml_list.c
  16. +446
    -0
      dml_packet.c
  17. +128
    -0
      dml_packet.h
  18. +217
    -0
      dml_poll.c
  19. +36
    -0
      dml_poll.h
  20. +199
    -0
      dml_reflector.c
  21. +221
    -0
      dml_route.c
  22. +33
    -0
      dml_route.h
  23. +102
    -0
      dml_server.c
  24. +29
    -0
      dml_server.h
  25. +171
    -0
      dml_stream.c
  26. +38
    -0
      dml_stream.h
  27. +188
    -0
      dml_stream_client.c
  28. +3
    -0
      dml_stream_client.conf
  29. +357
    -0
      dml_streamer_ogg.c
  30. +12
    -0
      dml_streamer_ogg.conf
  31. +767
    -0
      dmld.c
  32. +1
    -0
      dmld.conf
  33. +7
    -0
      key.txt

+ 8
- 0
.gitignore View File

@ -0,0 +1,8 @@
*.pem
*.o
*.d
dmld
dml_list
dml_reflector
dml_streamer_ogg
dml_stream_client

+ 50
- 0
Makefile View File

@ -0,0 +1,50 @@
include build.mk
CFLAGS += -g -Wall -Werror
LDFLAGS += -lcrypto
DML_SRCS = \
dml_client.c \
dml_config.c \
dml_connection.c \
dml_crypto.c \
dml_id.c \
dml_packet.c \
dml_poll.c \
dml_route.c \
dml_server.c \
dml_stream.c
DML_OBJS = $(DML_SRCS:.c=.o)
all: dmld dml_list dml_reflector dml_streamer_ogg dml_stream_client
SRCS += $(DML_SRCS)
SRCS += dmld.c
dmld: $(DML_OBJS) dmld.o
SRCS += dml_list.c
dml_list: $(DML_OBJS) dml_list.o
SRCS += dml_reflector.c
dml_reflector: $(DML_OBJS) dml_reflector.o
SRCS += dml_streamer_ogg.c
dml_streamer_ogg: $(DML_OBJS) dml_streamer_ogg.o
SRCS += dml_stream_client.c
dml_stream_client: $(DML_OBJS) dml_stream_client.o
DEPS:=$(SRCS:.c=.d)
-include $(DEPS)
OBJS+=$(SRCS:.c=.o)
clean:
rm -rf $(OBJS) \
dml_list \
dml_reflector \
dml_streamer_ogg \
dml_stream_client

+ 98
- 0
build.mk View File

@ -0,0 +1,98 @@
# Some make rules to make output pretty....
# default ARFLAGS also has 'v', but we don't want it to be verbose.
ARFLAGS= -r
# make sure libs from /usr/local/lib are found
VPATH= /lib64 /usr/lib64 /usr/local/lib64 /lib /usr/lib /usr/local/lib
LIBTOOL=libtool
OS= $(shell uname -s)
HW= $(shell uname -m)
ifneq ($(OS), FreeBSD)
FLEX=flex
else
FLEX=/usr/local/bin/flex
endif
BUILDCC:=${CC}
BUILDLIBTOOL:=${LIBTOOL}
ifdef BUILDSYS
BUILDCC:=${BUILDSYS}-gcc
BUILDLIBTOOL:=${BUILDSYS}-libtool
endif
ifdef HOSTSYS
CC=${HOSTSYS}-gcc
LIBTOOL=${HOSTSYS}-libtool
CONF_HOST=--host=${HOSTSYS}
HW=$(HOSTSYS)
endif
%.o : %.c
@echo " CC $<"
@$(CC) -MMD $(CFLAGS) -c $< -o $@
%.o : %.il2c.c
@echo "LT CCil $<"
@${LIBTOOL} --quiet --mode=compile --tag=CC $(CC) -MMD $(CFLAGS) -c $< -o $@
@sed -e "s:\.il2c.c:\.il:" -i -i $*.il2c.d
%: %.o
@echo " LD $@"
@${LIBTOOL} --quiet --mode=link --tag=CC $(LINK.o) $(filter %.o,$^) $(LOADLIBS) $(LDLIBS) $($@_LDFLAGS) -o $@
%.lo: %.c
@echo "LT CC $<"
@${LIBTOOL} --quiet --mode=compile --tag=CC $(CC) -MMD $(CFLAGS) -c $< -o $@
@cat $(dir $*).libs/$(*F).d | sed -e "s:\.libs/::" -e "s:\.o:\.lo:" > $*.d
%.lo: %.il2c.c
@echo "LT ilCC $<"
@${LIBTOOL} --quiet --mode=compile --tag=CC $(CC) -MMD $(CFLAGS) -c $<
@cat $(dir $*).libs/$(*F).d | sed -e "s:\.libs/::" -e "s:\.o:\.lo:" -e "s:\.il2c.c:\.il:" > $*.d
define LIB_LINK
@echo "LT LD $@"
@${LIBTOOL} --quiet --mode=link --tag=CC $(CC) $(filter %.lo,$^) -o $@ $(LDFLAGS) $($@_LDFLAGS) -static-libtool-libs -rpath $(abspath $(@D))
@echo "LT INST $@"
@${LIBTOOL} --quiet --mode=install install $@ $(abspath $(@D))
@sed -i -i s\|=$(CURDIR)\|$(CURDIR)\|g $@
endef
%.so:
@echo "LT soLD $@"
@${LIBTOOL} --quiet --mode=link --tag=CC $(CC) $(filter %.lo,$^) -o $@ $(LDFLAGS) $($@_LDFLAGS)
(%): %
@echo " AR $^ in $@"
@$(AR) $(ARFLAGS) $@ $^
%.tab.c %.tab.h: %.y
@echo "BISON $<"
@bison --defines=$*.tab.h $< -o $*.tab.c
%.yy.c %.yy.h: %.l %.tab.h
@echo " FLEX $<"
@$(FLEX) --header-file=$*.yy.h -o $*.yy.c $<
# il2c: instruction list 2 c 'compiler'
%.il2c.c: %.il
@echo " IL2C $<"
@$(IL2C) $<
# dot -> pdf
%.pdf: %.dot
@echo " DOT $<"
@dot $< -o $@ -Tpdf
%.dtb: %.dts
@echo " DTC $<"
@dtc -I dts $< -O dtb -o $@
%.dtbo: %.dts
@echo " DTCo $<"
@dtc -I dts $< -O dtb -o $@

+ 29
- 0
dml.h View File

@ -0,0 +1,29 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INCLUDE_DML_H_
#define _INCLUDE_DML_H_
#include <stdint.h>
#include <stdbool.h>
#define DML_VERSION "0.1"
#define DML_ID_SIZE 32
#define DML_SIG_SIZE ((256 * 2) / 8)
#endif /* _INCLUDE_DML_H_ */

+ 126
- 0
dml_client.c View File

@ -0,0 +1,126 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dml_client.h"
#include "dml_server.h"
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
#include <netdb.h>
struct dml_client {
int fd;
char *host;
unsigned short port;
void (*connect_cb)(struct dml_client *dc, void *arg);
void *arg;
};
struct dml_client *dml_client_create(char *host, unsigned short port, void (*cb)(struct dml_client *dc, void *arg), void *arg)
{
struct dml_client *dc;
if (!port)
port = DML_SERVER_PORT;
dc = calloc(1, sizeof(struct dml_client));
if (!dc)
goto err_calloc;
dc->host = strdup(host);
if (!dc->host)
goto err_strdup;
dc->port = port;
dc->fd = -1;
dc->connect_cb = cb;
dc->arg = arg;
return dc;
err_strdup:
free(dc);
err_calloc:
return NULL;
}
int dml_client_connect(struct dml_client *dc)
{
struct addrinfo *result;
struct addrinfo *entry;
struct addrinfo hints = { 0 };
int error, i;
int sock = -1;
char *port;
if (asprintf(&port, "%d", dc->port) < 0)
goto err_asprintf;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(dc->host, port, &hints, &result);
if (error) {
goto err_getaddrinfo;
}
for (entry = result; entry; entry = entry->ai_next) {
sock = socket(entry->ai_family, entry->ai_socktype,
entry->ai_protocol);
if (sock >= 0) {
if (connect(sock, entry->ai_addr, entry->ai_addrlen)) {
close(sock);
sock = -1;
} else {
i = 1;
setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, &i, sizeof (int));
break;
}
}
}
freeaddrinfo(result);
if (sock < 0)
goto err_connect;
free(port);
dc->fd = sock;
dc->connect_cb(dc, dc->arg);
return 0;
err_connect:
err_getaddrinfo:
free(port);
err_asprintf:
return -1;
}
int dml_client_fd_get(struct dml_client *dc)
{
return dc->fd;
}

+ 27
- 0
dml_client.h View File

@ -0,0 +1,27 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INCLUDE_DML_CLIENT_H_
#define _INCLUDE_DML_CLIENT_H_
struct dml_client;
struct dml_client *dml_client_create(char *host, unsigned short port, void (*cb)(struct dml_client *, void *arg), void *arg);
int dml_client_fd_get(struct dml_client *dc);
int dml_client_connect(struct dml_client *dc);
#endif /* _INCLUDE_DML_CLIENT_H_ */

+ 97
- 0
dml_config.c View File

@ -0,0 +1,97 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dml_config.h"
#include <stdio.h>
#include <string.h>
struct dml_config {
struct dml_config *next;
char *key;
char *value;
};
static struct dml_config *config_list = NULL;
int dml_config_load(char *file)
{
FILE *fd;
char *rf;
fd = fopen(file, "r");
if (!fd)
goto err_fopen;
do {
char buffer[1025];
char *key, *value;
rf = fgets(buffer, 1024, fd);
while (strlen(buffer) && buffer[strlen(buffer)-1] == '\n')
buffer[strlen(buffer)-1] = 0;
key = strtok(buffer, " \t=");
value = strtok(NULL, "\n\r");
if (key && value) {
struct dml_config *conf;
while (value[0] == ' ' ||
value[0] == '\t' ||
value[0] == '=')
value++;
conf = calloc(1, sizeof(struct dml_config));
if (!conf)
goto err_calloc;
conf->key = strdup(key);
conf->value = strdup(value);
struct dml_config **entry;
for (entry = &config_list; *entry; entry = &(*entry)->next);
*entry = conf;
}
} while (rf);
fclose(fd);
return 0;
err_calloc:
fclose(fd);
err_fopen:
return -1;
}
char *dml_config_value(char *key, char *prev_value, char *def)
{
struct dml_config *entry;
for (entry = config_list; entry; entry = entry->next) {
if (prev_value && entry->value != prev_value)
continue;
if (prev_value) {
prev_value = NULL;
continue;
}
if (!strcmp(entry->key, key))
return entry->value;
}
return def;
}

+ 27
- 0
dml_config.h View File

@ -0,0 +1,27 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INCLUDE_DML_CONFIG_H_
#define _INCLUDE_DML_CONFIG_H_
#include <stdlib.h>
int dml_config_load(char *file);
char *dml_config_value(char *key, char *prev_value, char *def);
#endif /* _INCLUDE_DML_CONFIG_H_ */

+ 207
- 0
dml_connection.c View File

@ -0,0 +1,207 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dml_connection.h"
#include "dml_packet.h"
#include "dml_poll.h"
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
enum connection_rx_state {
CONNECTION_HEADER,
CONNECTION_PACKET,
};
struct dml_connection {
int fd;
enum connection_rx_state rx_state;
uint8_t rx_data[DML_PACKET_SIZE_MAX];
uint8_t rx_hdr[DML_PACKET_HEADER_SIZE];
size_t rx_pos;
size_t rx_len;
uint8_t tx_buf[DML_PACKET_HEADER_SIZE + DML_PACKET_SIZE_MAX];
size_t tx_pos;
size_t tx_len;
void *arg;
void (*rx_cb)(struct dml_connection *, void *, uint16_t id, uint16_t len, uint8_t *data);
int (*close_cb)(struct dml_connection *, void *);
};
struct dml_connection *dml_connection_create(int fd,
void *arg,
void (*rx_cb)(struct dml_connection *, void *, uint16_t id, uint16_t len, uint8_t *data),
int (*close_cb)(struct dml_connection *, void *)
)
{
struct dml_connection *dc;
int flags;
dc = calloc(1, sizeof(struct dml_connection));
if (!dc)
goto err_calloc;
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0)
goto err_fcntl;
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
dc->fd = fd;
dc->rx_state = CONNECTION_HEADER;
dc->rx_cb = rx_cb;
dc->close_cb = close_cb;
dc->arg = arg;
dml_poll_add(dc, (int (*)(void *))dml_connection_handle, (int (*)(void *))dml_connection_handle, NULL);
// printf("new connection fd: %d\n", fd);
dml_poll_fd_set(dc, fd);
dml_poll_in_set(dc, true);
dml_poll_out_set(dc, false);
return dc;
err_fcntl:
free(dc);
err_calloc:
return NULL;
}
int dml_connection_destroy(struct dml_connection *dc)
{
// printf("close %p fd: %d\n", dc, dc->fd);
close(dc->fd);
free(dc);
return 0;
}
int dml_connection_fd_get(struct dml_connection *dc)
{
return dc->fd;
}
int dml_connection_handle(struct dml_connection *dc)
{
// printf("handle %p\n", dc);
ssize_t r = 0;
switch (dc->rx_state) {
case CONNECTION_HEADER: {
r = read(dc->fd, dc->rx_hdr + dc->rx_pos,
DML_PACKET_HEADER_SIZE - dc->rx_pos);
if (r > 0) {
dc->rx_pos += r;
}
if (dc->rx_pos == DML_PACKET_HEADER_SIZE) {
dc->rx_state = CONNECTION_PACKET;
dc->rx_len = dc->rx_hdr[3] + (dc->rx_hdr[2] << 8);
dc->rx_pos = 0;
}
break;
}
case CONNECTION_PACKET: {
r = read(dc->fd, dc->rx_data + dc->rx_pos,
dc->rx_len - dc->rx_pos);
if (r > 0) {
dc->rx_pos += r;
}
if (dc->rx_pos == dc->rx_len) {
dc->rx_state = CONNECTION_HEADER;
uint16_t id = dc->rx_hdr[1] + (dc->rx_hdr[0] << 8);
uint16_t len = dc->rx_len;
dc->rx_pos = 0;
dc->rx_cb(dc, dc->arg, id, len, dc->rx_data);
}
break;
}
}
if (r == 0 || (r < 0 && errno != EAGAIN)) {
dml_poll_remove(dc);
if (dc->close_cb)
return dc->close_cb(dc, dc->arg);
}
if (dc->tx_len) {
r = write(dc->fd, dc->tx_buf + dc->tx_pos, dc->tx_len - dc->tx_pos);
if (r >= 0) {
dc->tx_pos += r;
}
if (dc->tx_pos >= dc->tx_len) {
dml_poll_out_set(dc, false);
dc->tx_len = 0;
}
}
return 0;
}
int dml_connection_send(struct dml_connection *dc, void *datav, uint16_t id, uint16_t len)
{
uint8_t *data = datav;
if (dc->tx_len)
return -1;
dc->tx_buf[0] = id >> 8;
dc->tx_buf[1] = id & 0xff;
dc->tx_buf[2] = len >> 8;
dc->tx_buf[3] = len & 0xff;
ssize_t r;
r = write(dc->fd, dc->tx_buf, 4);
dc->tx_pos = r >= 0 ? 4 - r : 0;
if (r == 4) {
r = write(dc->fd, data, len);
if (r < 0)
r = 0;
} else {
r = 0;
}
dc->tx_pos += len - r;
if (dc->tx_pos < dc->tx_len) {
memcpy(dc->tx_buf + dc->tx_pos, data + len, len - r);
dml_poll_out_set(dc, true);
dc->tx_len = len + 4;
}
return 0;
}
bool dml_connection_send_empty(struct dml_connection *dc)
{
return !dc->tx_len;
}
int dml_connection_send_data(struct dml_connection *dc, void *datav, uint16_t id, uint16_t len)
{
// For now we just map to the control connection, add UDP stuff later...
return dml_connection_send(dc, datav, id, len);
}

+ 39
- 0
dml_connection.h View File

@ -0,0 +1,39 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INCLUDE_DML_CONNECTION_H_
#define _INCLUDE_DML_CONNECTION_H_
#include <stdint.h>
#include <stdbool.h>
struct dml_connection;
struct dml_connection *dml_connection_create(int fd,
void *arg,
void (*rx_cb)(struct dml_connection *, void *, uint16_t id, uint16_t len, uint8_t *data),
int (*close_cb)(struct dml_connection *, void *)
);
int dml_connection_destroy(struct dml_connection *dc);
int dml_connection_fd_get(struct dml_connection *dc);
int dml_connection_handle(struct dml_connection *dc);
int dml_connection_send(struct dml_connection *dc, void *datav, uint16_t id, uint16_t len);
bool dml_connection_send_empty(struct dml_connection *dc);
int dml_connection_send_data(struct dml_connection *dc, void *datav, uint16_t id, uint16_t len);
#endif /* _INCLUDE_DML_CONNECTION_H_ */

+ 307
- 0
dml_crypto.c View File

@ -0,0 +1,307 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dml_crypto.h"
#include "dml_stream.h"
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <string.h>
X509_STORE *x509_store;
STACK_OF(X509) *certchain;
int dml_crypto_init(char *ca_file, char *ca_dir)
{
/* Make sure we can find everything in the certificates */
OpenSSL_add_all_algorithms();
x509_store = X509_STORE_new();
if (!x509_store)
goto err_new;
if (ca_file || ca_dir) {
if (!X509_STORE_load_locations(x509_store, ca_file, ca_dir)) {
goto err_load;
}
// printf("Loadded store locations\n");
}
return 0;
err_load:
X509_STORE_free(x509_store);
err_new:
x509_store = NULL;
return -1;
}
struct dml_crypto_key *dml_crypto_key_create(void)
{
return calloc(1, sizeof(struct dml_crypto_key));
}
static void free_chain(STACK_OF(X509) *chain)
{
if (!chain)
return;
X509 *c;
while ((c = sk_X509_pop(chain)))
X509_free(c);
sk_X509_free(chain);
}
int dml_crypto_cert_add_verify(void *certdata, size_t size, uint8_t id[DML_ID_SIZE])
{
STACK_OF(X509 *chain);
uint8_t *data = certdata;
char *name;
chain = sk_X509_new_null();
if (!chain)
return -1;
while (size > 2) {
X509 *cert;
int certsize = (data[0] << 8) | data[1];
const unsigned char *cert_data = data + 2;
// printf("Cert: %zd %d\n", size, certsize);
if (certsize > size - 2)
break;
cert = d2i_X509(NULL, &cert_data, certsize);
if (!cert)
break;
// printf("cert: %p\n", cert);
sk_X509_push(chain, cert);
data += certsize + 2;
size -= certsize + 2;
}
if (sk_X509_num(chain) < 1)
goto err_stack;
X509 *cert = sk_X509_pop(chain);
// printf("1st cert %p\n", cert);
X509_STORE_CTX *ctx = X509_STORE_CTX_new();
if (!ctx)
goto err_ctx;
if (X509_STORE_CTX_init(ctx, x509_store, cert, chain) != 1) {
X509_STORE_CTX_free(ctx);
goto err_ctx;
}
int rc = X509_verify_cert(ctx);
// int err = X509_STORE_CTX_get_error(ctx);
X509_STORE_CTX_free(ctx);
// printf("rc: %d: %d: %s\n", rc, err, get_validation_errstr(err));
if (rc != 1)
goto err_verify;
struct dml_stream *ds = dml_stream_by_id(id);
if (!ds)
goto err_stream;
name = dml_stream_name_get(ds);
if (!name)
goto err_name;
rc = X509_check_host(cert, name, 0, 0, NULL);
// printf("rc: %d\n", rc);
struct dml_crypto_key *dk = dml_stream_crypto_get(ds);
if (!dk) {
dk = dml_crypto_key_create();
dml_stream_crypto_set(ds, dk);
} else {
free_chain(dk->chain);
X509_free(dk->cert);
EC_KEY_free(dk->ec_key);
}
dk->chain = chain;
dk->cert = cert;
EVP_PKEY *evp_key = X509_get_pubkey(cert);
if (!evp_key)
goto err_key;
if (EVP_PKEY_type(evp_key->type) != EVP_PKEY_EC)
goto err_key_type;
/* only 256 bits EC for now */
if (EVP_PKEY_bits(evp_key) != 256)
goto err_bits;
dk->ec_key = EVP_PKEY_get1_EC_KEY(evp_key);
EVP_PKEY_free(evp_key);
return !(rc == 1);
err_bits:
err_key_type:
EVP_PKEY_free(evp_key);
err_key:
err_name:
err_stream:
err_verify:
X509_free(cert);
err_ctx:
free_chain(chain);
err_stack:
return -1;
}
/* load a pem file */
int dml_crypto_load_cert(char *file)
{
int ret = -1;
X509 *cert;
certchain = sk_X509_new_null();
FILE *fp = fopen(file, "r");
if (!fp)
goto err_fopen;
while ((cert = PEM_read_X509(fp, NULL, NULL, NULL))) {
ret = 0;
sk_X509_push(certchain, cert);
}
fclose(fp);
return ret;
err_fopen:
return -1;
}
int dml_crypto_cert_get(void **bincert, size_t *size)
{
unsigned char *der = NULL;
int bytes, i;
uint8_t *bin = NULL;
size_t binsize = 0;
if (!certchain)
return -1;
for (i = 0; i < sk_X509_num(certchain); i++) {
X509 *cert = sk_X509_value(certchain, i);
bytes = i2d_X509(cert, &der);
if (bytes >= 0) {
bin = realloc(bin, binsize + sizeof(uint16_t) + bytes);
bin[binsize + 0] = (bytes >> 8) & 0xff;
bin[binsize + 1] = (bytes) & 0xff;
memcpy(bin + binsize + 2, der, bytes);
binsize += sizeof(uint16_t) + bytes;
free(der);
}
}
*size = binsize;
*bincert = bin;
return 0;
}
struct dml_crypto_key *dml_crypto_private_load(char *file)
{
struct dml_crypto_key *dk;
EVP_PKEY *evp_key;
FILE *fp;
dk = calloc(1, sizeof(struct dml_crypto_key));
if (!dk)
goto err_malloc;
fp = fopen(file, "r");
if (!fp)
goto err_fopen;
evp_key = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
dk->ec_key = EVP_PKEY_get1_EC_KEY(evp_key);
EVP_PKEY_free(evp_key);
fclose(fp);
return dk;
err_fopen:
free(dk);
err_malloc:
return NULL;
}
struct dml_crypto_key *dml_crypto_public_get(uint8_t id[DML_ID_SIZE])
{
struct dml_stream *ds = dml_stream_by_id(id);
if (!ds)
return NULL;
struct dml_crypto_key *dk = dml_stream_crypto_get(ds);
if (!dk)
return NULL;
return dk;
}
bool dml_crypto_verify(void *data, size_t len, uint8_t sig[DML_SIG_SIZE], struct dml_crypto_key *dk)
{
uint8_t digest[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, data, len);
SHA256_Final(digest, &sha256);
ECDSA_SIG *ecsig = ECDSA_SIG_new();
BN_bin2bn(sig, 32, ecsig->r);
BN_bin2bn(sig + 32, 32, ecsig->s);
int ret = ECDSA_do_verify(digest, SHA256_DIGEST_LENGTH, ecsig, dk->ec_key);
ECDSA_SIG_free(ecsig);
return ret;
}
int dml_crypto_sign(uint8_t sig[DML_SIG_SIZE], void *data, size_t len, struct dml_crypto_key *dk)
{
uint8_t digest[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, data, len);
SHA256_Final(digest, &sha256);
ECDSA_SIG *ecsig = ECDSA_do_sign(digest, SHA256_DIGEST_LENGTH, dk->ec_key);
BN_bn2bin(ecsig->r, sig);
BN_bn2bin(ecsig->s, sig + 32);
ECDSA_SIG_free(ecsig);
return 0;
}
void dml_crypto_key_free(struct dml_crypto_key *dk)
{
if (!dk)
return;
if (dk->ec_key)
EC_KEY_free(dk->ec_key);
free(dk);
}

+ 47
- 0
dml_crypto.h View File

@ -0,0 +1,47 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INCLUDE_DML_CRYPTO_H_
#define _INCLUDE_DML_CRYPTO_H_
#include "dml.h"
#include <openssl/pem.h>
struct dml_crypto_key {
EC_KEY *ec_key;
X509 *cert;
STACK_OF(X509) *chain;
};
int dml_crypto_init(char *ca_file, char *ca_dir);
int dml_crypto_cert_add_verify(void *cert, size_t size, uint8_t id[DML_ID_SIZE]);
int dml_crypto_load_cert(char *file);
int dml_crypto_cert_get(void **cert, size_t *size);
struct dml_crypto_key *dml_crypto_private_load(char *file);
struct dml_crypto_key *dml_crypto_public_get(uint8_t id[DML_ID_SIZE]);
int dml_crypto_sign(uint8_t sig[DML_SIG_SIZE], void *data, size_t len, struct dml_crypto_key *dk);
bool dml_crypto_verify(void *data, size_t len, uint8_t sig[DML_SIG_SIZE], struct dml_crypto_key *dk);
void dml_crypto_key_free(struct dml_crypto_key *);
#endif /* _INCLUDE_DML_CRYPTO_H_ */

+ 106
- 0
dml_id.c View File

@ -0,0 +1,106 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
#include "dml_id.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <openssl/sha.h>
static char assert1[SHA256_DIGEST_LENGTH - DML_ID_SIZE] __attribute__ ((unused));
static char assert2[DML_ID_SIZE - SHA256_DIGEST_LENGTH] __attribute__ ((unused));
int dml_id_gen(uint8_t id[DML_ID_SIZE], uint8_t version, uint32_t bps,
char *mime, char *name, char *alias, char *description)
{
SHA256_CTX sha256;
uint8_t vbps[5];
vbps[0] = version;
vbps[1] = (bps >> 24) & 0xff;
vbps[2] = (bps >> 16) & 0xff;
vbps[3] = (bps >> 8) & 0xff;
vbps[4] = (bps) & 0xff;
SHA256_Init(&sha256);
SHA256_Update(&sha256, vbps, sizeof(vbps));
SHA256_Update(&sha256, mime, strlen(mime));
SHA256_Update(&sha256, name, strlen(name));
SHA256_Update(&sha256, alias, strlen(alias));
SHA256_Update(&sha256, description, strlen(description));
SHA256_Final(id, &sha256);
return 0;
}
char *dml_id_str(uint8_t id[DML_ID_SIZE])
{
char *str;
asprintf(&str,
"%02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x",
id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7],
id[8], id[9], id[10], id[11], id[12], id[13], id[14], id[15],
id[16], id[17], id[18], id[19], id[20], id[21], id[22], id[23],
id[24], id[25], id[26], id[27], id[28], id[29], id[30], id[31]);
return str;
}
int dml_str_id(uint8_t id[DML_ID_SIZE], char *str)
{
int i;
if (strlen(str) < DML_ID_SIZE * 2)
return -1;
for (i = 0; i < DML_ID_SIZE; i++) {
uint8_t byte = 0;
if (str[0] >= '0' && str[0] <= '9')
byte += str[0] - '0';
else if (tolower(str[0]) >= 'a' && tolower(str[0]) <= 'f')
byte += tolower(str[0]) - 'a' + 10;
else
return -1;
byte <<= 4;
str++;
if (str[0] >= '0' && str[0] <= '9')
byte += str[0] - '0';
else if (tolower(str[0]) >= 'a' && tolower(str[0]) <= 'f')
byte += tolower(str[0]) - 'a' + 10;
else
return -1;
str++;
id[i] = byte;
}
return 0;
}

+ 30
- 0
dml_id.h View File

@ -0,0 +1,30 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INCLUDE_DML_ID_H_
#define _INCLUDE_DML_ID_H_
#include "dml.h"
int dml_id_gen(uint8_t id[DML_ID_SIZE], uint8_t version, uint32_t bps,
char *mime, char *name, char *alias, char *description);
char *dml_id_str(uint8_t id[DML_ID_SIZE]);
int dml_str_id(uint8_t id[DML_ID_SIZE], char *str);
#endif /* _INCLUDE_DML_ID_H_ */

+ 148
- 0
dml_list.c View File

@ -0,0 +1,148 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dml_client.h"
#include "dml_connection.h"
#include "dml_poll.h"
#include "dml_packet.h"
#include "dml.h"
#include "dml_id.h"
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
struct info {
uint8_t id[DML_ID_SIZE];
struct info *next;
};
struct info *info_list;
int info_add(uint8_t id[DML_ID_SIZE])
{
struct info *entry;
for (entry = info_list; entry; entry = entry->next) {
if (!memcmp(entry->id, id, DML_ID_SIZE))
return -1;
}
entry = calloc(1, sizeof(struct info));
memcpy(entry->id, id, DML_ID_SIZE);
entry->next = info_list;
info_list = entry;
return 0;
}
void rx_packet(struct dml_connection *dc, void *arg,
uint16_t id, uint16_t len, uint8_t *data)
{
switch (id) {
case DML_PACKET_HELLO: {
char *ident;
uint32_t flags;
dml_packet_parse_hello(data, len, &flags, &ident);
printf("ident: '%s' flags: %08"PRIx32"\n", ident, flags);
free(ident);
break;
}
case DML_PACKET_ROUTE: {
uint8_t id[DML_ID_SIZE];
uint8_t hops;
dml_packet_parse_route(data, len, id, &hops);
char *idstr = dml_id_str(id);
printf("id: %s hops: %d\n", idstr, hops);
free(idstr);
if (!info_add(id)) {
dml_packet_send_req_description(dc, id);
}
break;
}
case DML_PACKET_DESCRIPTION: {
uint8_t desc_id[DML_ID_SIZE];
uint8_t version;
uint32_t bps;
char *mime, *name, *alias, *description;
dml_packet_parse_description(data, len, desc_id, &version,
&bps, &mime, &name, &alias, &description);
char *idstr = dml_id_str(desc_id);
uint8_t hash_id[DML_ID_SIZE];
dml_id_gen(hash_id, version, bps, mime, name, alias,
description);
bool hash_match = !memcmp(hash_id, desc_id, DML_ID_SIZE);
printf("id: %s\n\tmime: '%s'\n\tbps: %d\n\tname: '%s'\n"
"\talias: '%s'\n\tdescription: '%s'\n"
"\thash ok: %d\n",
idstr, mime, bps, name, alias, description,
hash_match);
free(idstr);
free(mime);
free(name);
free(alias);
free(description);
}
default:
break;
}
return;
}
int client_connection_close(struct dml_connection *dc, void *arg)
{
//TODO timeout and reconnect!
return dml_connection_destroy(dc);
}
void client_connect(struct dml_client *client, void *arg)
{
struct dml_connection *dc;
int fd;
fd = dml_client_fd_get(client);
dc = dml_connection_create(fd, client, rx_packet, client_connection_close);
dml_packet_send_hello(dc, DML_PACKET_HELLO_UPDATES, "dml_list " DML_VERSION);
}
int main(int argc, char **argv)
{
struct dml_client *dc;
dc = dml_client_create("localhost", 0, client_connect, NULL);
if (dml_client_connect(dc)) {
printf("Could not connect to server\n");
return -1;
}
dml_poll_loop();
return 0;
}

+ 446
- 0
dml_packet.c View File

@ -0,0 +1,446 @@
/*
Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dml_packet.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int dml_packet_send_hello(struct dml_connection *dc, uint32_t flags, char *ident)
{
uint8_t data[4 + strlen(ident)];
data[0] = (flags >> 24) & 0xff;
data[1] = (flags >> 16) & 0xff;
data[2] = (flags >> 8) & 0xff;
data[3] = (flags >> 0) & 0xff;
memcpy(data + 4, ident, strlen(ident));
return dml_connection_send(dc, data, DML_PACKET_HELLO, 4 + strlen(ident));
}
int dml_packet_parse_hello(uint8_t *data, uint16_t len, uint32_t *flags, char **ident)
{
if (len < 4)
return -1;
if (flags)
*flags = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
if (ident) {
*ident = malloc(len - 4 + 1);
if (!*ident)
return -1;
(*ident)[len - 4] = 0;
memcpy(*ident, data + 4, len - 4);
}
return 0;
}
int dml_packet_send_description(struct dml_connection *dc,
uint8_t id[DML_ID_SIZE], uint8_t version, uint32_t bps, char *mime,
char *name, char *alias, char *description)
{
uint8_t data[DML_ID_SIZE + 1 + 4 + strlen(mime) + 1 +
strlen(name) + 1 + strlen(alias) + 1 + strlen(description) + 1];
size_t pos = 0;
if (version != DML_PACKET_DESCRIPTION_VERSION_0)
return -1;
memcpy(data, id, DML_ID_SIZE);
pos += DML_ID_SIZE;
data[pos] = version;
pos++;
data[pos + 0] = (bps >> 24) & 0xff;
data[pos + 1] = (bps >> 16) & 0xff;
data[pos + 2] = (bps >> 8) & 0xff;
data[pos + 3] = (bps >> 0) & 0xff;
pos += 4;
strcpy((char *)data + pos, mime);
pos += strlen(mime) + 1;
strcpy((char *)data + pos, name);
pos += strlen(name) + 1;
strcpy((char *)data + pos, alias);
pos += strlen(alias) + 1;
strcpy((char *)data + pos, description);
pos += strlen(description) + 1;
return dml_connection_send(dc, data, DML_PACKET_DESCRIPTION, pos);
}
int dml_packet_parse_description(uint8_t *data, uint16_t len,
uint8_t id[DML_ID_SIZE], uint8_t *version, uint32_t *bps, char **mime,
char **name, char **alias, char **description)
{
size_t pos_mime, pos_name, pos_alias, pos_description;
size_t size_mime, size_name, size_alias, size_description;
if (len < (DML_ID_SIZE + 1 + 4))
return -1;
*version = data[DML_ID_SIZE];
if (*version != DML_PACKET_DESCRIPTION_VERSION_0)
return -1;
memcpy(id, data, DML_ID_SIZE);
*bps =
(data[DML_ID_SIZE + 1] << 24) |
(data[DML_ID_SIZE + 2] << 16) |
(data[DML_ID_SIZE + 3] << 8) |
(data[DML_ID_SIZE + 4]);
pos_mime = DML_ID_SIZE + 1 + 4;
for (pos_name = pos_mime; pos_name < len && data[pos_name]; pos_name++);
if (pos_name < len - 1)
pos_name++;
for (pos_alias = pos_name; pos_alias < len && data[pos_alias]; pos_alias++);
if (pos_alias < len - 1)
pos_alias++;
for (pos_description = pos_alias; pos_description < len && data[pos_description]; pos_description++);
if (pos_description < len - 1)
pos_description++;
size_mime = pos_name - pos_mime;
size_name = pos_alias - pos_name;
size_alias = pos_description - pos_alias;
size_description = len - pos_description;
if (mime) {
*mime = malloc(size_mime);
if (*mime) {
memcpy(*mime, data + pos_mime, size_mime);
}
}
if (name) {
*name = malloc(size_name);
if (*name) {
memcpy(*name, data + pos_name, size_name);
}
}
if (alias) {
*alias = malloc(size_alias);
if (*alias) {
memcpy(*alias, data + pos_alias, size_alias);
}
}
if (description) {
*description = malloc(size_description);
if (*description) {
memcpy(*description, data + pos_description, size_description);
}
}
return 0;
}
int dml_packet_send_route(struct dml_connection *dc,
uint8_t id[DML_ID_SIZE], uint8_t hops)
{
uint8_t data[DML_ID_SIZE + 1];
memcpy(data, id, DML_ID_SIZE);
data[DML_ID_SIZE] = hops;
return dml_connection_send(dc, data, DML_PACKET_ROUTE, sizeof(data));
}
int dml_packet_parse_route(uint8_t *data, uint16_t len,
uint8_t id[DML_ID_SIZE], uint8_t *hops)
{
if (len < DML_ID_SIZE + 1)
return -1;
memcpy(id, data, DML_ID_SIZE);
if (hops)
*hops = data[DML_ID_SIZE];
return 0;
}
int dml_packet_send_req_description(struct dml_connection *dc,
uint8_t id_req[DML_ID_SIZE])
{
return dml_connection_send(dc, id_req, DML_PACKET_REQ_DESCRIPTION, DML_ID_SIZE);
}
int dml_packet_parse_req_description(uint8_t *data, uint16_t len,
uint8_t id_req[DML_ID_SIZE])
{
if (len < DML_ID_SIZE)
return -1;
memcpy(id_req, data, DML_ID_SIZE);
return 0;
}
int dml_packet_send_req_certificate(struct dml_connection *dc,
uint8_t id_req[DML_ID_SIZE])
{
return dml_connection_send(dc, id_req, DML_PACKET_REQ_CERTIFICATE, DML_ID_SIZE);
}
int dml_packet_parse_req_certificate(uint8_t *data, uint16_t len,
uint8_t id_req[DML_ID_SIZE])
{
if (len < DML_ID_SIZE)
return -1;
memcpy(id_req, data, DML_ID_SIZE);
return 0;
}
int dml_packet_send_req_header(struct dml_connection *dc,
uint8_t id_req[DML_ID_SIZE])
{
return dml_connection_send(dc, id_req, DML_PACKET_REQ_HEADER, DML_ID_SIZE);
}
int dml_packet_parse_req_header(uint8_t *data, uint16_t len,
uint8_t id_req[DML_ID_SIZE])
{
if (len < DML_ID_SIZE)
return -1;
memcpy(id_req, data, DML_ID_SIZE);
return 0;
}
int dml_packet_send_certificate(struct dml_connection *dc,
uint8_t id[DML_ID_SIZE], void *data, size_t len)
{
uint8_t payload[DML_ID_SIZE + len];
memcpy(payload, id, DML_ID_SIZE);
memcpy(payload + DML_ID_SIZE, data, len);
return dml_connection_send(dc, payload, DML_PACKET_CERTIFICATE, DML_ID_SIZE + len);
}
int dml_packet_parse_certificate(uint8_t *data, uint16_t len,
uint8_t id[DML_ID_SIZE], void **cert_data, size_t *cert_len)
{
uint8_t *data8 = data;
size_t plen;
if (len < DML_ID_SIZE)
return -1;
plen = len - DML_ID_SIZE;
memcpy(id, data, DML_ID_SIZE);
*cert_len = plen;
*cert_data = malloc(plen);
if (*cert_data) {
memcpy(*cert_data, data8 + DML_ID_SIZE, plen);
return 0;
}
return -1;
}