mirror of
https://github.com/svpcom/wfb-ng.git
synced 2025-02-15 05:23:49 -04:00
Add channel encryption
This commit is contained in:
parent
4722a7bcf9
commit
17692c2c96
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,3 +2,6 @@
|
||||
*.a
|
||||
rx
|
||||
tx
|
||||
rx.key
|
||||
tx.key
|
||||
keygen
|
||||
|
6
Makefile
6
Makefile
@ -1,8 +1,8 @@
|
||||
|
||||
LDFLAGS=-lrt -lpcap
|
||||
LDFLAGS=-lrt -lpcap -lsodium
|
||||
CPPFLAGS=-Wall -g
|
||||
|
||||
all: rx tx
|
||||
all: rx tx keygen
|
||||
|
||||
%.o: %.c *.h
|
||||
gcc -c -o $@ $< $(CPPFLAGS)
|
||||
@ -17,6 +17,8 @@ rx: rx.o radiotap.o fec.o wifibroadcast.o
|
||||
tx: tx.o fec.o wifibroadcast.o
|
||||
g++ -o $@ $^ $(LDFLAGS)
|
||||
|
||||
keygen: keygen.o
|
||||
gcc -o $@ $^ $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f rx tx *~ *.o
|
||||
|
57
keygen.c
Normal file
57
keygen.c
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- c -*-
|
||||
*/
|
||||
// Copyright (C) 2017 Vasily Evseenko <svpcom@p2ptech.org>
|
||||
// based on wifibroadcast (c)2015 befinitiv
|
||||
|
||||
/*
|
||||
* 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; version 2.
|
||||
*
|
||||
* 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, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sodium.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned char tx_publickey[crypto_box_PUBLICKEYBYTES];
|
||||
unsigned char tx_secretkey[crypto_box_SECRETKEYBYTES];
|
||||
unsigned char rx_publickey[crypto_box_PUBLICKEYBYTES];
|
||||
unsigned char rx_secretkey[crypto_box_SECRETKEYBYTES];
|
||||
FILE *fp;
|
||||
|
||||
crypto_box_keypair(tx_publickey, tx_secretkey);
|
||||
crypto_box_keypair(rx_publickey, rx_secretkey);
|
||||
|
||||
if((fp = fopen("tx.key", "w")) == NULL)
|
||||
{
|
||||
perror("Unable to save tx.key");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fwrite(tx_secretkey, crypto_box_SECRETKEYBYTES, 1, fp);
|
||||
fwrite(rx_publickey, crypto_box_PUBLICKEYBYTES, 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
if((fp = fopen("rx.key", "w")) == NULL)
|
||||
{
|
||||
perror("Unable to save rx.key");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fwrite(rx_secretkey, crypto_box_SECRETKEYBYTES, 1, fp);
|
||||
fwrite(tx_publickey, crypto_box_PUBLICKEYBYTES, 1, fp);
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
103
rx.cpp
103
rx.cpp
@ -190,7 +190,7 @@ void Receiver::loop_iter(void)
|
||||
}
|
||||
|
||||
|
||||
LocalAggregator::LocalAggregator(const string &client_addr, int client_port, int k, int n) : fec_k(k), fec_n(n), seq(0), rx_ring_front(0), rx_ring_alloc(0), proc_ring_last(0)
|
||||
LocalAggregator::LocalAggregator(const string &client_addr, int client_port, int k, int n, const string &keypair) : fec_k(k), fec_n(n), seq(0), rx_ring_front(0), rx_ring_alloc(0), proc_ring_last(0)
|
||||
{
|
||||
sockfd = open_udp_socket(client_addr, client_port);
|
||||
fec_p = fec_new(fec_k, fec_n);
|
||||
@ -213,6 +213,15 @@ LocalAggregator::LocalAggregator(const string &client_addr, int client_port, int
|
||||
{
|
||||
proc_ring[ring_idx] = -1;
|
||||
}
|
||||
|
||||
FILE *fp;
|
||||
if((fp = fopen(keypair.c_str(), "r")) == NULL)
|
||||
{
|
||||
throw runtime_error(string_format("Unable to open %s: %s", keypair.c_str(), strerror(errno)));
|
||||
}
|
||||
if (fread(rx_secretkey, crypto_box_SECRETKEYBYTES, 1, fp) != 1) throw runtime_error(string_format("Unable to read rx secret key: %s", strerror(errno)));
|
||||
if (fread(tx_publickey, crypto_box_PUBLICKEYBYTES, 1, fp) != 1) throw runtime_error(string_format("Unable to read tx public key: %s", strerror(errno)));
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
|
||||
@ -317,27 +326,71 @@ int LocalAggregator::get_block_ring_idx(int block_idx)
|
||||
|
||||
void LocalAggregator::process_packet(const uint8_t *buf, size_t size)
|
||||
{
|
||||
if(size < sizeof(wblock_hdr_t) + sizeof(wpacket_hdr_t))
|
||||
{
|
||||
fprintf(stderr, "short packet (fec header)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (size > MAX_FEC_PAYLOAD + sizeof(wblock_hdr_t))
|
||||
if(size == 0) return;
|
||||
if (size > MAX_FORWARDER_PACKET_SIZE)
|
||||
{
|
||||
fprintf(stderr, "long packet (fec payload)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wblock_hdr_t *block_hdr = (wblock_hdr_t*)buf;
|
||||
|
||||
if (block_hdr->fragment_idx >= fec_n)
|
||||
switch(buf[0])
|
||||
{
|
||||
fprintf(stderr, "invalid fragment_idx: %d\n", block_hdr->fragment_idx);
|
||||
case WFB_PACKET_DATA:
|
||||
if(size < sizeof(wblock_hdr_t) + sizeof(wpacket_hdr_t))
|
||||
{
|
||||
fprintf(stderr, "short packet (fec header)\n");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case WFB_PACKET_KEY:
|
||||
if(size != sizeof(wsession_key_t))
|
||||
{
|
||||
fprintf(stderr, "invalid session key packet\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(crypto_box_open_easy(session_key,
|
||||
((wsession_key_t*)buf)->session_key, sizeof(wsession_key_t::session_key), ((wsession_key_t*)buf)->nonce,
|
||||
tx_publickey, rx_secretkey) != 0)
|
||||
{
|
||||
fprintf(stderr, "unable to decrypt session key\n");
|
||||
}
|
||||
return;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unknown packet type 0x%x\n", buf[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
int ring_idx = get_block_ring_idx(block_hdr->block_idx);
|
||||
// Truncate block_idx to 8 bit
|
||||
uint8_t decrypted[MAX_FEC_PAYLOAD];
|
||||
long long unsigned int decrypted_len;
|
||||
wblock_hdr_t *block_hdr = (wblock_hdr_t*)buf;
|
||||
|
||||
if (crypto_aead_chacha20poly1305_decrypt(decrypted, &decrypted_len,
|
||||
NULL,
|
||||
buf + sizeof(wblock_hdr_t), size - sizeof(wblock_hdr_t),
|
||||
buf,
|
||||
sizeof(wblock_hdr_t),
|
||||
(uint8_t*)(&(block_hdr->nonce)), session_key) != 0)
|
||||
{
|
||||
fprintf(stderr, "unable to decrypt packet #0x%Lx\n", (long long unsigned int)(block_hdr->nonce));
|
||||
return;
|
||||
}
|
||||
|
||||
assert(decrypted_len <= MAX_FEC_PAYLOAD);
|
||||
|
||||
uint8_t block_idx = (uint8_t)((block_hdr->nonce >> 8) & 0xff);
|
||||
uint8_t fragment_idx = (uint8_t)(block_hdr->nonce & 0xff);
|
||||
|
||||
if (fragment_idx >= fec_n)
|
||||
{
|
||||
fprintf(stderr, "invalid fragment_idx: %d\n", fragment_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
int ring_idx = get_block_ring_idx(block_idx);
|
||||
|
||||
//ignore already processed blocks
|
||||
if (ring_idx < 0) return;
|
||||
@ -345,12 +398,12 @@ void LocalAggregator::process_packet(const uint8_t *buf, size_t size)
|
||||
rx_ring_item_t *p = &rx_ring[ring_idx];
|
||||
|
||||
//ignore already processed fragments
|
||||
if (p->fragment_map[block_hdr->fragment_idx]) return;
|
||||
if (p->fragment_map[fragment_idx]) return;
|
||||
|
||||
memset(p->fragments[block_hdr->fragment_idx], '\0', MAX_FEC_PAYLOAD);
|
||||
memcpy(p->fragments[block_hdr->fragment_idx], buf + sizeof(wblock_hdr_t), size - sizeof(wblock_hdr_t));
|
||||
memset(p->fragments[fragment_idx], '\0', MAX_FEC_PAYLOAD);
|
||||
memcpy(p->fragments[fragment_idx], decrypted, decrypted_len);
|
||||
|
||||
p->fragment_map[block_hdr->fragment_idx] = 1;
|
||||
p->fragment_map[fragment_idx] = 1;
|
||||
p->has_fragments += 1;
|
||||
|
||||
if(ring_idx == rx_ring_front)
|
||||
@ -448,9 +501,13 @@ int main(int argc, char* const *argv)
|
||||
int srv_port=0;
|
||||
string client_addr="127.0.0.1";
|
||||
rx_mode_t rx_mode = LOCAL;
|
||||
string keypair = "rx.key";
|
||||
|
||||
while ((opt = getopt(argc, argv, "fa:k:n:c:u:p:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "K:fa:k:n:c:u:p:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'K':
|
||||
keypair = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
rx_mode = FORWARDER;
|
||||
break;
|
||||
@ -475,10 +532,10 @@ int main(int argc, char* const *argv)
|
||||
break;
|
||||
default: /* '?' */
|
||||
show_usage:
|
||||
fprintf(stderr, "Local receiver: %s [-k RS_K] [-n RS_N] [-c client_addr] [-u client_port] [-p radio_port] interface1 [interface2] ...\n", argv[0]);
|
||||
fprintf(stderr, "Local receiver: %s [-K rx_key] [-k RS_K] [-n RS_N] [-c client_addr] [-u client_port] [-p radio_port] interface1 [interface2] ...\n", argv[0]);
|
||||
fprintf(stderr, "Remote (forwarder): %s -f [-c client_addr] [-u client_port] [-p radio_port] interface1 [interface2] ...\n", argv[0]);
|
||||
fprintf(stderr, "Remote (aggregator): %s -a server_port [-k RS_K] [-n RS_N] [-c client_addr] [-u client_port]\n", argv[0]);
|
||||
fprintf(stderr, "Default: k=%d, n=%d, connect=%s:%d, radio_port=%d\n", k, n, client_addr.c_str(), client_port, radio_port);
|
||||
fprintf(stderr, "Remote (aggregator): %s -a server_port [-K rx_key] [-k RS_K] [-n RS_N] [-c client_addr] [-u client_port]\n", argv[0]);
|
||||
fprintf(stderr, "Default: K='%s', k=%d, n=%d, connect=%s:%d, radio_port=%d\n", keypair.c_str(), k, n, client_addr.c_str(), client_port, radio_port);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@ -495,7 +552,7 @@ int main(int argc, char* const *argv)
|
||||
|
||||
shared_ptr<Aggregator> agg;
|
||||
if(rx_mode == LOCAL){
|
||||
agg = shared_ptr<LocalAggregator>(new LocalAggregator(client_addr, client_port, k, n));
|
||||
agg = shared_ptr<LocalAggregator>(new LocalAggregator(client_addr, client_port, k, n, keypair));
|
||||
}else{
|
||||
agg = shared_ptr<RemoteAggregator>(new RemoteAggregator(client_addr, client_port));
|
||||
}
|
||||
@ -535,7 +592,7 @@ int main(int argc, char* const *argv)
|
||||
|
||||
uint8_t buf[MAX_FORWARDER_PACKET_SIZE];
|
||||
int fd = open_udp_socket_for_rx(srv_port);
|
||||
LocalAggregator agg(client_addr, client_port, k, n);
|
||||
LocalAggregator agg(client_addr, client_port, k, n, keypair);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
|
7
rx.hpp
7
rx.hpp
@ -83,7 +83,7 @@ static inline int modN(int x, int base)
|
||||
class LocalAggregator : public Aggregator
|
||||
{
|
||||
public:
|
||||
LocalAggregator(const string &client_addr, int client_port, int k, int n);
|
||||
LocalAggregator(const string &client_addr, int client_port, int k, int n, const string &keypair);
|
||||
~LocalAggregator();
|
||||
virtual void process_packet(const uint8_t *buf, size_t size);
|
||||
private:
|
||||
@ -102,6 +102,11 @@ private:
|
||||
int rx_ring_alloc; // number of allocated entries
|
||||
int proc_ring[PROC_RING_SIZE];
|
||||
int proc_ring_last; // index to add processed packet
|
||||
|
||||
// rx->tx keypair
|
||||
uint8_t rx_secretkey[crypto_box_SECRETKEYBYTES];
|
||||
uint8_t tx_publickey[crypto_box_PUBLICKEYBYTES];
|
||||
uint8_t session_key[crypto_aead_chacha20poly1305_KEYBYTES];
|
||||
};
|
||||
|
||||
class Receiver
|
||||
|
186
tx.cpp
186
tx.cpp
@ -40,11 +40,51 @@ extern "C"
|
||||
#include "wifibroadcast.hpp"
|
||||
#include "tx.hpp"
|
||||
|
||||
Transmitter::Transmitter(int k, int n, const string &keypair): fec_k(k), fec_n(n), block_idx(0),
|
||||
fragment_idx(0), seq(0),
|
||||
max_packet_size(0)
|
||||
{
|
||||
fec_p = fec_new(fec_k, fec_n);
|
||||
|
||||
Transmitter::Transmitter(const char *wlan, int k, int n, uint8_t radio_port) : wlan(wlan), fec_k(k), fec_n(n), block_idx(0),
|
||||
fragment_idx(0), seq(0),
|
||||
radio_port(radio_port), max_packet_size(0),
|
||||
ieee80211_seq(0)
|
||||
block = new uint8_t*[fec_n];
|
||||
for(int i=0; i < fec_n; i++)
|
||||
{
|
||||
block[i] = new uint8_t[MAX_FEC_PAYLOAD];
|
||||
}
|
||||
|
||||
FILE *fp;
|
||||
if((fp = fopen(keypair.c_str(), "r")) == NULL)
|
||||
{
|
||||
throw runtime_error(string_format("Unable to open %s: %s", keypair.c_str(), strerror(errno)));
|
||||
}
|
||||
if (fread(tx_secretkey, crypto_box_SECRETKEYBYTES, 1, fp) != 1) throw runtime_error(string_format("Unable to read tx secret key: %s", strerror(errno)));
|
||||
if (fread(rx_publickey, crypto_box_PUBLICKEYBYTES, 1, fp) != 1) throw runtime_error(string_format("Unable to read rx public key: %s", strerror(errno)));
|
||||
fclose(fp);
|
||||
|
||||
randombytes_buf(session_key, sizeof(session_key));
|
||||
session_key_packet.packet_type = WFB_PACKET_KEY;
|
||||
randombytes_buf(session_key_packet.nonce, sizeof(session_key_packet.nonce));
|
||||
if (crypto_box_easy(session_key_packet.session_key, session_key, sizeof(session_key),
|
||||
session_key_packet.nonce, rx_publickey, tx_secretkey) != 0)
|
||||
{
|
||||
throw runtime_error("Unable to make session key!");
|
||||
}
|
||||
}
|
||||
|
||||
Transmitter::~Transmitter()
|
||||
{
|
||||
for(int i=0; i < fec_n; i++)
|
||||
{
|
||||
delete block[i];
|
||||
}
|
||||
delete block;
|
||||
|
||||
fec_free(fec_p);
|
||||
}
|
||||
|
||||
PcapTransmitter::PcapTransmitter(int k, int n, const string &keypair, uint8_t radio_port, const char *wlan) : Transmitter(k, n, keypair),
|
||||
radio_port(radio_port), wlan(wlan),
|
||||
ieee80211_seq(0)
|
||||
{
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
ppcap = pcap_create(wlan, errbuf);
|
||||
@ -59,38 +99,21 @@ Transmitter::Transmitter(const char *wlan, int k, int n, uint8_t radio_port) :
|
||||
if (pcap_activate(ppcap) !=0) throw runtime_error(string_format("pcap_activate failed: %s", pcap_geterr(ppcap)));
|
||||
//if (pcap_setnonblock(ppcap, 1, errbuf) != 0) throw runtime_error(string_format("set_nonblock failed: %s", errbuf));
|
||||
|
||||
fec_p = fec_new(fec_k, fec_n);
|
||||
|
||||
block = new uint8_t*[fec_n];
|
||||
for(int i=0; i < fec_n; i++)
|
||||
{
|
||||
block[i] = new uint8_t[MAX_FEC_PAYLOAD];
|
||||
}
|
||||
}
|
||||
|
||||
Transmitter::~Transmitter()
|
||||
{
|
||||
for(int i=0; i < fec_n; i++)
|
||||
{
|
||||
delete block[i];
|
||||
}
|
||||
delete block;
|
||||
|
||||
fec_free(fec_p);
|
||||
pcap_close(ppcap);
|
||||
}
|
||||
|
||||
|
||||
void Transmitter::send_block_fragment(size_t packet_size)
|
||||
void PcapTransmitter::inject_packet(const uint8_t *buf, size_t size)
|
||||
{
|
||||
uint8_t txbuf[MAX_PACKET_SIZE];
|
||||
uint8_t *p = txbuf;
|
||||
wblock_hdr_t block_hdr;
|
||||
block_hdr.block_idx = block_idx;
|
||||
block_hdr.fragment_idx = fragment_idx;
|
||||
|
||||
assert(size <= MAX_FORWARDER_PACKET_SIZE);
|
||||
|
||||
// radiotap header
|
||||
memcpy(p, radiotap_header, sizeof(radiotap_header));
|
||||
p += sizeof(radiotap_header);
|
||||
|
||||
// ieee80211 header
|
||||
memcpy(p, ieee80211_header, sizeof(ieee80211_header));
|
||||
p[SRC_MAC_LASTBYTE] = radio_port;
|
||||
p[DST_MAC_LASTBYTE] = radio_port;
|
||||
@ -98,10 +121,10 @@ void Transmitter::send_block_fragment(size_t packet_size)
|
||||
p[FRAME_SEQ_HB] = (ieee80211_seq >> 8) & 0xff;
|
||||
ieee80211_seq += 16;
|
||||
p += sizeof(ieee80211_header);
|
||||
memcpy(p, &block_hdr, sizeof(block_hdr));
|
||||
p += sizeof(block_hdr);
|
||||
memcpy(p, block[fragment_idx], packet_size);
|
||||
p += packet_size;
|
||||
|
||||
// FEC data
|
||||
memcpy(p, buf, size);
|
||||
p += size;
|
||||
|
||||
if (pcap_inject(ppcap, txbuf, p - txbuf) != p - txbuf)
|
||||
{
|
||||
@ -109,9 +132,41 @@ void Transmitter::send_block_fragment(size_t packet_size)
|
||||
}
|
||||
}
|
||||
|
||||
PcapTransmitter::~PcapTransmitter()
|
||||
{
|
||||
pcap_close(ppcap);
|
||||
}
|
||||
|
||||
|
||||
void Transmitter::send_block_fragment(size_t packet_size)
|
||||
{
|
||||
uint8_t ciphertext[MAX_FORWARDER_PACKET_SIZE];
|
||||
wblock_hdr_t *block_hdr = (wblock_hdr_t*)ciphertext;
|
||||
long long unsigned int ciphertext_len;
|
||||
|
||||
assert(packet_size <= MAX_FEC_PAYLOAD);
|
||||
|
||||
block_hdr->packet_type = WFB_PACKET_DATA;
|
||||
block_hdr->nonce = ((block_idx & BLOCK_IDX_MASK) << 8) + fragment_idx;
|
||||
|
||||
// encrypted payload
|
||||
crypto_aead_chacha20poly1305_encrypt(ciphertext + sizeof(wblock_hdr_t), &ciphertext_len,
|
||||
block[fragment_idx], packet_size,
|
||||
(uint8_t*)block_hdr, sizeof(wblock_hdr_t),
|
||||
NULL, (uint8_t*)(&(block_hdr->nonce)), session_key);
|
||||
|
||||
inject_packet(ciphertext, sizeof(wblock_hdr_t) + ciphertext_len);
|
||||
}
|
||||
|
||||
void Transmitter::send_session_key(void)
|
||||
{
|
||||
inject_packet((uint8_t*)&session_key_packet, sizeof(session_key_packet));
|
||||
}
|
||||
|
||||
void Transmitter::send_packet(const uint8_t *buf, size_t size)
|
||||
{
|
||||
wpacket_hdr_t packet_hdr;
|
||||
assert(size <= MAX_PAYLOAD_SIZE);
|
||||
|
||||
packet_hdr.seq = seq++;
|
||||
packet_hdr.packet_size = size;
|
||||
@ -135,18 +190,6 @@ void Transmitter::send_packet(const uint8_t *buf, size_t size)
|
||||
max_packet_size = 0;
|
||||
}
|
||||
|
||||
|
||||
void normal_rx(Transmitter &t, int fd)
|
||||
{
|
||||
uint8_t buf[MAX_PAYLOAD_SIZE];
|
||||
for(;;)
|
||||
{
|
||||
ssize_t rsize = recv(fd, buf, sizeof(buf), 0);
|
||||
if (rsize < 0) throw runtime_error(string_format("Error receiving packet: %s", strerror(errno)));
|
||||
t.send_packet(buf, rsize);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t get_system_time(void) // in milliseconds
|
||||
{
|
||||
struct timeval te;
|
||||
@ -154,7 +197,26 @@ uint64_t get_system_time(void) // in milliseconds
|
||||
return te.tv_sec * 1000LL + te.tv_usec / 1000;
|
||||
}
|
||||
|
||||
void mavlink_rx(Transmitter &t, int fd, int agg_latency)
|
||||
void normal_rx(Transmitter *t, int fd)
|
||||
{
|
||||
uint8_t buf[MAX_PAYLOAD_SIZE];
|
||||
uint64_t session_key_announce_ts = 0;
|
||||
for(;;)
|
||||
{
|
||||
ssize_t rsize = recv(fd, buf, sizeof(buf), 0);
|
||||
if (rsize < 0) throw runtime_error(string_format("Error receiving packet: %s", strerror(errno)));
|
||||
uint64_t cur_ts = get_system_time();
|
||||
if (cur_ts >= session_key_announce_ts)
|
||||
{
|
||||
// Announce session key
|
||||
t->send_session_key();
|
||||
session_key_announce_ts = cur_ts + SESSION_KEY_ANNOUNCE_MSEC;
|
||||
}
|
||||
t->send_packet(buf, rsize);
|
||||
}
|
||||
}
|
||||
|
||||
void mavlink_rx(Transmitter *t, int fd, int agg_latency)
|
||||
{
|
||||
struct pollfd fds[1];
|
||||
|
||||
@ -171,6 +233,7 @@ void mavlink_rx(Transmitter &t, int fd, int agg_latency)
|
||||
size_t agg_size = 0;
|
||||
uint8_t agg_buf[MAX_PAYLOAD_SIZE];
|
||||
uint64_t expire_ts = get_system_time() + agg_latency;
|
||||
uint64_t session_key_announce_ts = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
@ -186,7 +249,14 @@ void mavlink_rx(Transmitter &t, int fd, int agg_latency)
|
||||
{
|
||||
if(agg_size > 0)
|
||||
{
|
||||
t.send_packet(agg_buf, agg_size);
|
||||
cur_ts = get_system_time();
|
||||
if (cur_ts >= session_key_announce_ts)
|
||||
{
|
||||
// Announce session key
|
||||
t->send_session_key();
|
||||
session_key_announce_ts = cur_ts + SESSION_KEY_ANNOUNCE_MSEC;
|
||||
}
|
||||
t->send_packet(agg_buf, agg_size);
|
||||
agg_size = 0;
|
||||
}
|
||||
expire_ts = get_system_time() + agg_latency;
|
||||
@ -209,7 +279,14 @@ void mavlink_rx(Transmitter &t, int fd, int agg_latency)
|
||||
{
|
||||
if(agg_size > 0)
|
||||
{
|
||||
t.send_packet(agg_buf, agg_size);
|
||||
cur_ts = get_system_time();
|
||||
if (cur_ts >= session_key_announce_ts)
|
||||
{
|
||||
// Announce session key
|
||||
t->send_session_key();
|
||||
session_key_announce_ts = cur_ts + SESSION_KEY_ANNOUNCE_MSEC;
|
||||
}
|
||||
t->send_packet(agg_buf, agg_size);
|
||||
agg_size = 0;
|
||||
}
|
||||
expire_ts = get_system_time() + agg_latency;
|
||||
@ -229,9 +306,13 @@ int main(int argc, char * const *argv)
|
||||
int udp_port=5600;
|
||||
bool mavlink_mode = false;
|
||||
int mavlink_agg_latency = 0;
|
||||
string keypair = "tx.key";
|
||||
|
||||
while ((opt = getopt(argc, argv, "m:k:n:u:r:p:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "K:m:k:n:u:r:p:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'K':
|
||||
keypair = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
mavlink_mode = true;
|
||||
mavlink_agg_latency = atoi(optarg);
|
||||
@ -250,9 +331,9 @@ int main(int argc, char * const *argv)
|
||||
break;
|
||||
default: /* '?' */
|
||||
show_usage:
|
||||
fprintf(stderr, "Usage: %s [-m mavlink_agg_in_ms] [-k RS_K] [-n RS_N] [-u udp_port] [-p radio_port] interface\n",
|
||||
fprintf(stderr, "Usage: %s [-K tx_key] [-m mavlink_agg_in_ms] [-k RS_K] [-n RS_N] [-u udp_port] [-p radio_port] interface\n",
|
||||
argv[0]);
|
||||
fprintf(stderr, "Default: k=%d, n=%d, udp_port=%d, radio_port=%d\n", k, n, udp_port, radio_port);
|
||||
fprintf(stderr, "Default: K='%s', k=%d, n=%d, udp_port=%d, radio_port=%d\n", keypair.c_str(), k, n, udp_port, radio_port);
|
||||
fprintf(stderr, "Radio MTU: %lu\n", MAX_PAYLOAD_SIZE);
|
||||
exit(1);
|
||||
}
|
||||
@ -265,14 +346,15 @@ int main(int argc, char * const *argv)
|
||||
try
|
||||
{
|
||||
int fd = open_udp_socket_for_rx(udp_port);
|
||||
Transmitter t(argv[optind], k, n, radio_port);
|
||||
shared_ptr<Transmitter>t = shared_ptr<PcapTransmitter>(new PcapTransmitter(k, n, keypair, radio_port, argv[optind]));
|
||||
//shared_ptr<Transmitter>t = shared_ptr<UdpTransmitter>(new UdpTransmitter(k, n, keypair, "127.0.0.1", 5601));
|
||||
|
||||
if (mavlink_mode)
|
||||
{
|
||||
mavlink_rx(t, fd, mavlink_agg_latency);
|
||||
mavlink_rx(t.get(), fd, mavlink_agg_latency);
|
||||
}else
|
||||
{
|
||||
normal_rx(t, fd);
|
||||
normal_rx(t.get(), fd);
|
||||
}
|
||||
}catch(runtime_error &e)
|
||||
{
|
||||
|
81
tx.hpp
81
tx.hpp
@ -18,28 +18,93 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
using namespace std;
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Transmitter
|
||||
{
|
||||
public:
|
||||
Transmitter(const char* wlan, int k, int m, uint8_t radio_port);
|
||||
~Transmitter();
|
||||
Transmitter(int k, int m, const string &keypair);
|
||||
virtual ~Transmitter();
|
||||
void send_packet(const uint8_t *buf, size_t size);
|
||||
void send_session_key(void);
|
||||
|
||||
protected:
|
||||
virtual void inject_packet(const uint8_t *buf, size_t size) = 0;
|
||||
|
||||
private:
|
||||
void send_block_fragment(size_t packet_size);
|
||||
string wlan;
|
||||
pcap_t *ppcap;
|
||||
fec_t* fec_p;
|
||||
int fec_k; // RS number of primary fragments in block
|
||||
int fec_n; // RS total number of fragments in block
|
||||
uint8_t block_idx;
|
||||
uint64_t block_idx; //block_idx << 8 + fragment_idx = nonce (64bit)
|
||||
uint8_t fragment_idx;
|
||||
uint32_t seq;
|
||||
uint8_t radio_port;
|
||||
uint8_t** block;
|
||||
size_t max_packet_size;
|
||||
uint16_t ieee80211_seq;
|
||||
|
||||
// tx->rx keypair
|
||||
uint8_t tx_secretkey[crypto_box_SECRETKEYBYTES];
|
||||
uint8_t rx_publickey[crypto_box_PUBLICKEYBYTES];
|
||||
uint8_t session_key[crypto_aead_chacha20poly1305_KEYBYTES];
|
||||
wsession_key_t session_key_packet;
|
||||
};
|
||||
|
||||
|
||||
class PcapTransmitter : public Transmitter
|
||||
{
|
||||
public:
|
||||
PcapTransmitter(int k, int m, const string &keypair, uint8_t radio_port, const char* wlan);
|
||||
virtual ~PcapTransmitter();
|
||||
|
||||
private:
|
||||
virtual void inject_packet(const uint8_t *buf, size_t size);
|
||||
uint8_t radio_port;
|
||||
string wlan;
|
||||
uint16_t ieee80211_seq;
|
||||
pcap_t *ppcap;
|
||||
};
|
||||
|
||||
|
||||
class UdpTransmitter : public Transmitter
|
||||
{
|
||||
public:
|
||||
UdpTransmitter(int k, int m, const string &keypair, const string &client_addr, int client_port) : Transmitter(k, m, keypair)
|
||||
{
|
||||
sockfd = open_udp_socket(client_addr, client_port);
|
||||
}
|
||||
|
||||
virtual ~UdpTransmitter()
|
||||
{
|
||||
close(sockfd);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void inject_packet(const uint8_t *buf, size_t size)
|
||||
{
|
||||
send(sockfd, buf, size, 0);
|
||||
}
|
||||
|
||||
int open_udp_socket(const string &client_addr, int client_port)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) throw runtime_error(string_format("Error opening socket: %s", strerror(errno)));
|
||||
|
||||
bzero((char *) &saddr, sizeof(saddr));
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_addr.s_addr = inet_addr(client_addr.c_str());
|
||||
saddr.sin_port = htons((unsigned short)client_port);
|
||||
|
||||
if (connect(fd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0)
|
||||
{
|
||||
throw runtime_error(string_format("Connect error: %s", strerror(errno)));
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int sockfd;
|
||||
};
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sodium.h>
|
||||
|
||||
#define MAX_PACKET_SIZE 1510
|
||||
#define MAX_RX_INTERFACES 8
|
||||
@ -89,9 +90,19 @@ static uint8_t ieee80211_header[] = {
|
||||
0x00, 0x00, // seq num << 4 + fragment num
|
||||
};
|
||||
|
||||
|
||||
// nounce: 56bit block_idx + 8bit fragment_idx
|
||||
|
||||
#define BLOCK_IDX_MASK ((1LU << 56) - 1)
|
||||
|
||||
#define WFB_PACKET_DATA 0x1
|
||||
#define WFB_PACKET_KEY 0x2
|
||||
|
||||
#define SESSION_KEY_ANNOUNCE_MSEC 1000
|
||||
|
||||
typedef struct {
|
||||
uint8_t block_idx;
|
||||
uint8_t fragment_idx;
|
||||
uint8_t packet_type;
|
||||
uint64_t nonce;
|
||||
} __attribute__ ((packed)) wblock_hdr_t;
|
||||
|
||||
typedef struct {
|
||||
@ -99,9 +110,14 @@ typedef struct {
|
||||
uint16_t packet_size;
|
||||
} __attribute__ ((packed)) wpacket_hdr_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t packet_type;
|
||||
uint8_t nonce[crypto_box_NONCEBYTES];
|
||||
uint8_t session_key[crypto_aead_chacha20poly1305_KEYBYTES + crypto_box_MACBYTES]; // encrypted session key
|
||||
} __attribute__ ((packed)) wsession_key_t;
|
||||
|
||||
#define MAX_PAYLOAD_SIZE (MAX_PACKET_SIZE - sizeof(radiotap_header) - sizeof(ieee80211_header) - sizeof(wblock_hdr_t) - sizeof(wpacket_hdr_t))
|
||||
#define MAX_FEC_PAYLOAD (MAX_PACKET_SIZE - sizeof(radiotap_header) - sizeof(ieee80211_header) - sizeof(wblock_hdr_t))
|
||||
#define MAX_PAYLOAD_SIZE (MAX_PACKET_SIZE - sizeof(radiotap_header) - sizeof(ieee80211_header) - sizeof(wblock_hdr_t) - crypto_aead_chacha20poly1305_ABYTES - sizeof(wpacket_hdr_t))
|
||||
#define MAX_FEC_PAYLOAD (MAX_PACKET_SIZE - sizeof(radiotap_header) - sizeof(ieee80211_header) - sizeof(wblock_hdr_t) - crypto_aead_chacha20poly1305_ABYTES)
|
||||
#define MAX_FORWARDER_PACKET_SIZE (MAX_PACKET_SIZE - sizeof(radiotap_header) - sizeof(ieee80211_header))
|
||||
|
||||
int open_udp_socket_for_rx(int port);
|
||||
|
Loading…
Reference in New Issue
Block a user