Merge branch 'main' into patch-1
This commit is contained in:
commit
b4c851b39e
42
.github/workflows/cmake.yml
vendored
Normal file
42
.github/workflows/cmake.yml
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
name: CMake
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||||
|
BUILD_TYPE: Release
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
# The CMake configure and build commands are platform agnostic and should work equally
|
||||||
|
# well on Windows or Mac. You can convert this to a matrix build if you need
|
||||||
|
# cross-platform coverage.
|
||||||
|
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install xmllint
|
||||||
|
run: sudo apt-get install libpcaudio-dev
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
|
||||||
|
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
|
||||||
|
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
# Build your program with the given configuration
|
||||||
|
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
working-directory: ${{github.workspace}}/build
|
||||||
|
# Execute tests defined by the CMake configuration.
|
||||||
|
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
||||||
|
run: ctest -C ${{env.BUILD_TYPE}}
|
||||||
|
|
@ -2,26 +2,27 @@ cmake_minimum_required(VERSION 3.1)
|
|||||||
|
|
||||||
project(googerteller VERSION 1.0
|
project(googerteller VERSION 1.0
|
||||||
DESCRIPTION "Audible feedback on Google communications"
|
DESCRIPTION "Audible feedback on Google communications"
|
||||||
LANGUAGES CXX)
|
LANGUAGES CXX C)
|
||||||
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17 CACHE STRING "The C++ standard to use")
|
set(CMAKE_CXX_STANDARD 17 CACHE STRING "The C++ standard to use")
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_CXX_EXTENSIONS ON)
|
set(CMAKE_CXX_EXTENSIONS ON)
|
||||||
|
|
||||||
#add_library(support STATIC ext/powerblog/h2o-pp.cc
|
add_custom_target(Work ALL DEPENDS configs.hh)
|
||||||
# ext/powerblog/ext/simplesocket/swrappers.cc
|
|
||||||
# ext/powerblog/ext/simplesocket/comboaddress.cc
|
|
||||||
# ext/powerblog/ext/simplesocket/sclasses.cc
|
|
||||||
# ext/fmt-7.1.3/src/format.cc)
|
|
||||||
|
|
||||||
|
add_executable(teller teller.cc ext/lpm.c)
|
||||||
|
|
||||||
#target_include_directories(support PUBLIC ext/powerblog/ext/simplesocket ext/powerblog/ext ext/fmt-7.1.3/include/)
|
|
||||||
#target_link_libraries(support PUBLIC -lh2o-evloop -lssl -lcrypto Threads::Threads)
|
|
||||||
|
|
||||||
add_executable(teller teller.cc )
|
|
||||||
target_link_libraries(teller -lpcaudio -lpthread)
|
target_link_libraries(teller -lpcaudio -lpthread)
|
||||||
|
|
||||||
#enable_testing()
|
add_executable(testrunner testrunner.cc ext/lpm.c )
|
||||||
#add_test(testname testrunner)
|
target_link_libraries(testrunner -lpcaudio)
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
add_test(testname testrunner)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT configs.hh
|
||||||
|
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/make-built-in-config.sh ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
DEPENDS teller.conf trackers.conf
|
||||||
|
)
|
||||||
|
|
||||||
|
100
README.md
100
README.md
@ -2,20 +2,45 @@
|
|||||||
|
|
||||||
Audible feedback on just how much your browsing feeds into Google.
|
Audible feedback on just how much your browsing feeds into Google.
|
||||||
|
|
||||||
By bert@hubertnet.nl / https://berthub.eu/
|
By bert@hubertnet.nl / https://berthub.eu/
|
||||||
|
|
||||||
Makes a little bit of noise any time your computer sends a packet to a
|
Makes a little bit of noise any time your computer sends a packet to a
|
||||||
Google service, which excludes Google Cloud users.
|
tracker or a Google service, which excludes Google Cloud users.
|
||||||
|
|
||||||
Demo video [in this tweet](https://twitter.com/bert_hu_bert/status/1561466204602220544)
|
Demo video [in this tweet](https://twitter.com/bert_hu_bert/status/1561466204602220544)
|
||||||
|
|
||||||
|
[Blog post with more videos](https://berthub.eu/articles/posts/tracker-beeper/)
|
||||||
|
|
||||||
|
## Installing on OSX:
|
||||||
|
If need be, install Homebrew via https://brew.sh/ as this will allow you to
|
||||||
|
compile new software. To do so, copy paste the instruction under 'Install
|
||||||
|
Homebrew' into the terminal app ([Apple
|
||||||
|
help](https://support.apple.com/guide/terminal/open-or-quit-terminal-apd5265185d-f365-44cb-8b09-71a064a42125/mac)). This might take quite a while.
|
||||||
|
It will also ask for your password.
|
||||||
|
|
||||||
|
Then run:
|
||||||
|
```
|
||||||
|
brew tap robertjakub/teller
|
||||||
|
brew install --HEAD googerteller
|
||||||
|
```
|
||||||
|
|
||||||
|
To then start the noise, enter:
|
||||||
|
```
|
||||||
|
sudo tcpdump -nql | teller
|
||||||
|
```
|
||||||
|
And it should work. For the last command, it may also again ask you to enter your
|
||||||
|
password.
|
||||||
|
|
||||||
## How to compile
|
## How to compile
|
||||||
|
This will currently only work on Unix derived systems (like Linux, OSX and
|
||||||
|
FreeBSD).
|
||||||
|
|
||||||
You need a C++ compiler like `gcc-c++` and CMake for compiling the binary.
|
You need a C++ compiler like `gcc-c++` and CMake for compiling the binary.
|
||||||
|
|
||||||
You also need to install `libpcaudio` (`libpcaudio-dev` on Debian/Ubuntu, `pcaudiolib-devel` on Fedora/Red Hat, `pcaudiolib` on Arch/Manjaro).
|
You also need to install `libpcaudio` (`libpcaudio-dev` on Debian/Ubuntu, `pcaudiolib-devel` on Fedora/Red Hat, `pcaudiolib` on Arch/Manjaro).
|
||||||
|
For OSX [this is a bit more work](https://github.com/espeak-ng/pcaudiolib#mac-os)
|
||||||
|
|
||||||
Then run:
|
Then do:
|
||||||
|
|
||||||
```
|
```
|
||||||
cmake .
|
cmake .
|
||||||
@ -23,44 +48,30 @@ make
|
|||||||
```
|
```
|
||||||
|
|
||||||
## How to run
|
## How to run
|
||||||
Google is so large its IPv4 and IPv6 footprint can't be handled by tcpdump,
|
Start as:
|
||||||
or at least not efficiently. Therefore we need to define an ip(6)tables
|
|
||||||
`ipset`. This will first exclude Google Cloud, and then include all the
|
|
||||||
other Google IP addresses.
|
|
||||||
|
|
||||||
Install iptables 'ipset', and run (as root) the `ipset-setup.sh` script, or
|
|
||||||
execute:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
ipset create google-services hash:net
|
sudo tcpdump -nql | ./teller
|
||||||
for a in $(cat goog-cloud-prefixes.txt)
|
|
||||||
do
|
|
||||||
echo $a
|
|
||||||
ipset add google-services $a nomatch
|
|
||||||
done
|
|
||||||
for a in $(cat goog-prefixes.txt)
|
|
||||||
do
|
|
||||||
ipset add google-services $a
|
|
||||||
done
|
|
||||||
|
|
||||||
ipset create google-services6 hash:net family inet6
|
|
||||||
for a in $(cat goog-cloud-prefixes6.txt)
|
|
||||||
do
|
|
||||||
ipset add google-services6 $a nomatch
|
|
||||||
done
|
|
||||||
|
|
||||||
for a in $(cat goog-prefixes6.txt)
|
|
||||||
do
|
|
||||||
ipset add google-services6 $a
|
|
||||||
done
|
|
||||||
iptables -I OUTPUT -m set --match-set google-services dst -j NFLOG --nflog-group 20 --nflog-threshold 1
|
|
||||||
ip6tables -I OUTPUT -m set --match-set google-services6 dst -j NFLOG --nflog-group 20 --nflog-threshold 1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Then start as:
|
And cry.
|
||||||
```
|
|
||||||
sudo tcpdump -i nflog:20 -ln | ./teller
|
## Configuration
|
||||||
```
|
Tracker data is read from `tracker.conf` which you should only edit if
|
||||||
|
you've learned about more IP addresses for relevant trackers.
|
||||||
|
|
||||||
|
In `teller.conf` you can edit for each tracker where the noise should end up
|
||||||
|
(left or right channel), and what the frequency should be.
|
||||||
|
|
||||||
|
## Data source
|
||||||
|
The list of Google services IP addresses can be found on [this Google
|
||||||
|
support page](https://support.google.com/a/answer/10026322?hl=en).
|
||||||
|
|
||||||
|
Note that this splits out Google services and Google cloud user IP
|
||||||
|
addresses. However, it appears the Google services set includes the cloud IP
|
||||||
|
addresses, so you must check both sets before determining something is in
|
||||||
|
fact a Google service and not a Google customer.
|
||||||
|
|
||||||
|
# To run on a single process on Linux
|
||||||
|
|
||||||
Or, to track a single process, fe `firefox`, start it and run:
|
Or, to track a single process, fe `firefox`, start it and run:
|
||||||
|
|
||||||
@ -72,11 +83,10 @@ sudo bpftrace netsendmsg.bt |
|
|||||||
|
|
||||||
And cry.
|
And cry.
|
||||||
|
|
||||||
## Data source
|
## Dependencies
|
||||||
The list of Google services IP addresses can be found on [this Google
|
This software gratefully builds on:
|
||||||
support page](https://support.google.com/a/answer/10026322?hl=en).
|
|
||||||
|
|
||||||
Note that this splits out Google services and Google cloud user IP
|
* [doctest](https://github.com/doctest/doctest) testing framework
|
||||||
addresses. However, it appears the Google services set includes the cloud IP
|
* [lpm](https://github.com/rmind/liblpm) Longest Prefix Match library
|
||||||
addresses, so you must check both sets before determining something is in
|
* [Portable C Audio Library 1.2](https://github.com/espeak-ng/pcaudiolib) - which you need to install yourself
|
||||||
fact a Google service and not a Google customer.
|
* tcpdump of course
|
||||||
|
6580
ext/doctest.h
Normal file
6580
ext/doctest.h
Normal file
File diff suppressed because it is too large
Load Diff
420
ext/lpm.c
Normal file
420
ext/lpm.c
Normal file
@ -0,0 +1,420 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Mindaugas Rasiukevicius <rmind at noxt eu>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Use is subject to license terms, as specified in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Longest Prefix Match (LPM) library supporting IPv4 and IPv6.
|
||||||
|
*
|
||||||
|
* Algorithm:
|
||||||
|
*
|
||||||
|
* Each prefix gets its own hash map and all added prefixes are saved
|
||||||
|
* in a bitmap. On a lookup, we perform a linear scan of hash maps,
|
||||||
|
* iterating through the added prefixes only. Usually, there are only
|
||||||
|
* a few unique prefixes used and such simple algorithm is very efficient.
|
||||||
|
* With many IPv6 prefixes, the linear scan might become a bottleneck.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "lpm.h"
|
||||||
|
|
||||||
|
#define LPM_MAX_PREFIX (128)
|
||||||
|
#define LPM_MAX_WORDS (LPM_MAX_PREFIX >> 5)
|
||||||
|
#define LPM_TO_WORDS(x) ((x) >> 2)
|
||||||
|
#define LPM_HASH_STEP (8)
|
||||||
|
#define LPM_LEN_IDX(len) ((len) >> 4)
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define ASSERT assert
|
||||||
|
#else
|
||||||
|
#define ASSERT(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct lpm_ent {
|
||||||
|
struct lpm_ent *next;
|
||||||
|
void * val;
|
||||||
|
unsigned len;
|
||||||
|
uint8_t key[];
|
||||||
|
} lpm_ent_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned hashsize;
|
||||||
|
unsigned nitems;
|
||||||
|
lpm_ent_t ** bucket;
|
||||||
|
} lpm_hmap_t;
|
||||||
|
|
||||||
|
struct lpm {
|
||||||
|
uint32_t bitmask[LPM_MAX_WORDS];
|
||||||
|
void * defvals[2];
|
||||||
|
lpm_hmap_t prefix[LPM_MAX_PREFIX + 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t zero_address[LPM_MAX_WORDS];
|
||||||
|
|
||||||
|
lpm_t *
|
||||||
|
lpm_create(void)
|
||||||
|
{
|
||||||
|
lpm_t *lpm;
|
||||||
|
|
||||||
|
if ((lpm = calloc(1, sizeof(lpm_t))) == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return lpm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpm_clear(lpm_t *lpm, lpm_dtor_t dtor, void *arg)
|
||||||
|
{
|
||||||
|
for (unsigned n = 0; n <= LPM_MAX_PREFIX; n++) {
|
||||||
|
lpm_hmap_t *hmap = &lpm->prefix[n];
|
||||||
|
|
||||||
|
if (!hmap->hashsize) {
|
||||||
|
ASSERT(!hmap->bucket);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < hmap->hashsize; i++) {
|
||||||
|
lpm_ent_t *entry = hmap->bucket[i];
|
||||||
|
|
||||||
|
while (entry) {
|
||||||
|
lpm_ent_t *next = entry->next;
|
||||||
|
|
||||||
|
if (dtor) {
|
||||||
|
dtor(arg, entry->key,
|
||||||
|
entry->len, entry->val);
|
||||||
|
}
|
||||||
|
free(entry);
|
||||||
|
entry = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(hmap->bucket);
|
||||||
|
hmap->bucket = NULL;
|
||||||
|
hmap->hashsize = 0;
|
||||||
|
hmap->nitems = 0;
|
||||||
|
}
|
||||||
|
if (dtor) {
|
||||||
|
dtor(arg, zero_address, 4, lpm->defvals[0]);
|
||||||
|
dtor(arg, zero_address, 16, lpm->defvals[1]);
|
||||||
|
}
|
||||||
|
memset(lpm->bitmask, 0, sizeof(lpm->bitmask));
|
||||||
|
memset(lpm->defvals, 0, sizeof(lpm->defvals));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
lpm_destroy(lpm_t *lpm)
|
||||||
|
{
|
||||||
|
lpm_clear(lpm, NULL, NULL);
|
||||||
|
free(lpm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fnv1a_hash: Fowler-Noll-Vo hash function (FNV-1a variant).
|
||||||
|
*/
|
||||||
|
static uint32_t
|
||||||
|
fnv1a_hash(const void *buf, size_t len)
|
||||||
|
{
|
||||||
|
uint32_t hash = 2166136261UL;
|
||||||
|
const uint8_t *p = buf;
|
||||||
|
|
||||||
|
while (len--) {
|
||||||
|
hash ^= *p++;
|
||||||
|
hash *= 16777619U;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
hashmap_rehash(lpm_hmap_t *hmap, unsigned size)
|
||||||
|
{
|
||||||
|
lpm_ent_t **bucket;
|
||||||
|
unsigned hashsize;
|
||||||
|
|
||||||
|
for (hashsize = 1; hashsize < size; hashsize <<= 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((bucket = calloc(1, hashsize * sizeof(lpm_ent_t *))) == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (unsigned n = 0; n < hmap->hashsize; n++) {
|
||||||
|
lpm_ent_t *list = hmap->bucket[n];
|
||||||
|
|
||||||
|
while (list) {
|
||||||
|
lpm_ent_t *entry = list;
|
||||||
|
uint32_t hash = fnv1a_hash(entry->key, entry->len);
|
||||||
|
const unsigned i = hash & (hashsize - 1);
|
||||||
|
|
||||||
|
list = entry->next;
|
||||||
|
entry->next = bucket[i];
|
||||||
|
bucket[i] = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hmap->hashsize = hashsize;
|
||||||
|
free(hmap->bucket); // may be NULL
|
||||||
|
hmap->bucket = bucket;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static lpm_ent_t *
|
||||||
|
hashmap_insert(lpm_hmap_t *hmap, const void *key, size_t len)
|
||||||
|
{
|
||||||
|
const unsigned target = hmap->nitems + LPM_HASH_STEP;
|
||||||
|
const size_t entlen = offsetof(lpm_ent_t, key[len]);
|
||||||
|
uint32_t hash, i;
|
||||||
|
lpm_ent_t *entry;
|
||||||
|
|
||||||
|
if (hmap->hashsize < target && !hashmap_rehash(hmap, target)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = fnv1a_hash(key, len);
|
||||||
|
i = hash & (hmap->hashsize - 1);
|
||||||
|
entry = hmap->bucket[i];
|
||||||
|
while (entry) {
|
||||||
|
if (entry->len == len && memcmp(entry->key, key, len) == 0) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((entry = malloc(entlen)) != NULL) {
|
||||||
|
memcpy(entry->key, key, len);
|
||||||
|
entry->next = hmap->bucket[i];
|
||||||
|
entry->len = len;
|
||||||
|
|
||||||
|
hmap->bucket[i] = entry;
|
||||||
|
hmap->nitems++;
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static lpm_ent_t *
|
||||||
|
hashmap_lookup(lpm_hmap_t *hmap, const void *key, size_t len)
|
||||||
|
{
|
||||||
|
const uint32_t hash = fnv1a_hash(key, len);
|
||||||
|
const unsigned i = hash & (hmap->hashsize - 1);
|
||||||
|
lpm_ent_t *entry;
|
||||||
|
|
||||||
|
if (hmap->hashsize == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
entry = hmap->bucket[i];
|
||||||
|
|
||||||
|
while (entry) {
|
||||||
|
if (entry->len == len && memcmp(entry->key, key, len) == 0) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hashmap_remove(lpm_hmap_t *hmap, const void *key, size_t len)
|
||||||
|
{
|
||||||
|
const uint32_t hash = fnv1a_hash(key, len);
|
||||||
|
const unsigned i = hash & (hmap->hashsize - 1);
|
||||||
|
lpm_ent_t *prev = NULL, *entry;
|
||||||
|
|
||||||
|
if (hmap->hashsize == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
entry = hmap->bucket[i];
|
||||||
|
|
||||||
|
while (entry) {
|
||||||
|
if (entry->len == len && memcmp(entry->key, key, len) == 0) {
|
||||||
|
if (prev) {
|
||||||
|
prev->next = entry->next;
|
||||||
|
} else {
|
||||||
|
hmap->bucket[i] = entry->next;
|
||||||
|
}
|
||||||
|
free(entry);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
prev = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* compute_prefix: given the address and prefix length, compute and
|
||||||
|
* return the address prefix.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
compute_prefix(const unsigned nwords, const uint32_t *addr,
|
||||||
|
unsigned preflen, uint32_t *prefix)
|
||||||
|
{
|
||||||
|
uint32_t addr2[4];
|
||||||
|
|
||||||
|
if ((uintptr_t)addr & 3) {
|
||||||
|
/* Unaligned address: just copy for now. */
|
||||||
|
memcpy(addr2, addr, nwords * 4);
|
||||||
|
addr = addr2;
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < nwords; i++) {
|
||||||
|
if (preflen == 0) {
|
||||||
|
prefix[i] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (preflen < 32) {
|
||||||
|
uint32_t mask = htonl(0xffffffff << (32 - preflen));
|
||||||
|
prefix[i] = addr[i] & mask;
|
||||||
|
preflen = 0;
|
||||||
|
} else {
|
||||||
|
prefix[i] = addr[i];
|
||||||
|
preflen -= 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* lpm_insert: insert the CIDR into the LPM table.
|
||||||
|
*
|
||||||
|
* => Returns zero on success and -1 on failure.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lpm_insert(lpm_t *lpm, const void *addr,
|
||||||
|
size_t len, unsigned preflen, void *val)
|
||||||
|
{
|
||||||
|
const unsigned nwords = LPM_TO_WORDS(len);
|
||||||
|
uint32_t prefix[nwords];
|
||||||
|
lpm_ent_t *entry;
|
||||||
|
ASSERT(len == 4 || len == 16);
|
||||||
|
|
||||||
|
if (preflen == 0) {
|
||||||
|
/* 0-length prefix is a special case. */
|
||||||
|
lpm->defvals[LPM_LEN_IDX(len)] = val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
compute_prefix(nwords, addr, preflen, prefix);
|
||||||
|
entry = hashmap_insert(&lpm->prefix[preflen], prefix, len);
|
||||||
|
if (entry) {
|
||||||
|
const unsigned n = --preflen >> 5;
|
||||||
|
lpm->bitmask[n] |= 0x80000000U >> (preflen & 31);
|
||||||
|
entry->val = val;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* lpm_remove: remove the specified prefix.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lpm_remove(lpm_t *lpm, const void *addr, size_t len, unsigned preflen)
|
||||||
|
{
|
||||||
|
const unsigned nwords = LPM_TO_WORDS(len);
|
||||||
|
uint32_t prefix[nwords];
|
||||||
|
ASSERT(len == 4 || len == 16);
|
||||||
|
|
||||||
|
if (preflen == 0) {
|
||||||
|
lpm->defvals[LPM_LEN_IDX(len)] = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
compute_prefix(nwords, addr, preflen, prefix);
|
||||||
|
return hashmap_remove(&lpm->prefix[preflen], prefix, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* lpm_lookup: find the longest matching prefix given the IP address.
|
||||||
|
*
|
||||||
|
* => Returns the associated value on success or NULL on failure.
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
lpm_lookup(lpm_t *lpm, const void *addr, size_t len)
|
||||||
|
{
|
||||||
|
const unsigned nwords = LPM_TO_WORDS(len);
|
||||||
|
unsigned i, n = nwords;
|
||||||
|
uint32_t prefix[nwords];
|
||||||
|
|
||||||
|
while (n--) {
|
||||||
|
uint32_t bitmask = lpm->bitmask[n];
|
||||||
|
|
||||||
|
while ((i = ffs(bitmask)) != 0) {
|
||||||
|
const unsigned preflen = (32 * n) + (32 - --i);
|
||||||
|
lpm_hmap_t *hmap = &lpm->prefix[preflen];
|
||||||
|
lpm_ent_t *entry;
|
||||||
|
|
||||||
|
compute_prefix(nwords, addr, preflen, prefix);
|
||||||
|
entry = hashmap_lookup(hmap, prefix, len);
|
||||||
|
if (entry) {
|
||||||
|
return entry->val;
|
||||||
|
}
|
||||||
|
bitmask &= ~(1U << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lpm->defvals[LPM_LEN_IDX(len)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* lpm_lookup_prefix: return the value associated with a prefix
|
||||||
|
*
|
||||||
|
* => Returns the associated value on success or NULL on failure.
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
lpm_lookup_prefix(lpm_t *lpm, const void *addr, size_t len, unsigned preflen)
|
||||||
|
{
|
||||||
|
const unsigned nwords = LPM_TO_WORDS(len);
|
||||||
|
uint32_t prefix[nwords];
|
||||||
|
lpm_ent_t *entry;
|
||||||
|
ASSERT(len == 4 || len == 16);
|
||||||
|
|
||||||
|
if (preflen == 0) {
|
||||||
|
return lpm->defvals[LPM_LEN_IDX(len)];
|
||||||
|
}
|
||||||
|
compute_prefix(nwords, addr, preflen, prefix);
|
||||||
|
entry = hashmap_lookup(&lpm->prefix[preflen], prefix, len);
|
||||||
|
if (entry) {
|
||||||
|
return entry->val;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* lpm_strtobin: convert CIDR string to the binary IP address and mask.
|
||||||
|
*
|
||||||
|
* => The address will be in the network byte order.
|
||||||
|
* => Returns 0 on success or -1 on failure.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
lpm_strtobin(const char *cidr, void *addr, size_t *len, unsigned *preflen)
|
||||||
|
{
|
||||||
|
char *p, buf[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
|
strncpy(buf, cidr, sizeof(buf));
|
||||||
|
buf[sizeof(buf) - 1] = '\0';
|
||||||
|
|
||||||
|
if ((p = strchr(buf, '/')) != NULL) {
|
||||||
|
const ptrdiff_t off = p - buf;
|
||||||
|
*preflen = atoi(&buf[off + 1]);
|
||||||
|
buf[off] = '\0';
|
||||||
|
} else {
|
||||||
|
*preflen = LPM_MAX_PREFIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inet_pton(AF_INET6, buf, addr) == 1) {
|
||||||
|
*len = 16;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (inet_pton(AF_INET, buf, addr) == 1) {
|
||||||
|
if (*preflen == LPM_MAX_PREFIX) {
|
||||||
|
*preflen = 32;
|
||||||
|
}
|
||||||
|
*len = 4;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
28
ext/lpm.h
Normal file
28
ext/lpm.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Mindaugas Rasiukevicius <rmind at noxt eu>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Use is subject to license terms, as specified in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LPM_H_
|
||||||
|
#define _LPM_H_
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct lpm lpm_t;
|
||||||
|
typedef void (*lpm_dtor_t)(void *, const void *, size_t, void *);
|
||||||
|
|
||||||
|
lpm_t * lpm_create(void);
|
||||||
|
void lpm_destroy(lpm_t *);
|
||||||
|
void lpm_clear(lpm_t *, lpm_dtor_t, void *);
|
||||||
|
|
||||||
|
int lpm_insert(lpm_t *, const void *, size_t, unsigned, void *);
|
||||||
|
int lpm_remove(lpm_t *, const void *, size_t, unsigned);
|
||||||
|
void * lpm_lookup(lpm_t *, const void *, size_t);
|
||||||
|
void * lpm_lookup_prefix(lpm_t *, const void *, size_t, unsigned);
|
||||||
|
int lpm_strtobin(const char *, void *, size_t *, unsigned *);
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif
|
17169
ext/toml.hpp
Normal file
17169
ext/toml.hpp
Normal file
File diff suppressed because it is too large
Load Diff
38
lpmwrapper.hh
Normal file
38
lpmwrapper.hh
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
extern "C" {
|
||||||
|
#include "ext/lpm.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
class LPMWrapper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LPMWrapper()
|
||||||
|
{
|
||||||
|
d_lpm = lpm_create();
|
||||||
|
}
|
||||||
|
~LPMWrapper()
|
||||||
|
{
|
||||||
|
lpm_destroy(d_lpm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(const std::string& str, void* val=(void*)1)
|
||||||
|
{
|
||||||
|
char addr[16];
|
||||||
|
size_t len=sizeof(addr);
|
||||||
|
unsigned preflen=0;
|
||||||
|
lpm_strtobin(str.c_str(), addr, &len, &preflen);
|
||||||
|
if(lpm_insert(d_lpm, addr, len, preflen, val) < 0)
|
||||||
|
throw std::runtime_error("Error inserting prefix");
|
||||||
|
}
|
||||||
|
|
||||||
|
void* lookup(const char*str)
|
||||||
|
{
|
||||||
|
char addr[16];
|
||||||
|
size_t len=sizeof(addr);
|
||||||
|
unsigned preflen=0;
|
||||||
|
lpm_strtobin(str, addr, &len, &preflen);
|
||||||
|
return lpm_lookup(d_lpm, addr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
lpm_t* d_lpm;
|
||||||
|
};
|
12
make-built-in-config.sh
Executable file
12
make-built-in-config.sh
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
cd $1
|
||||||
|
(
|
||||||
|
echo \#pragma once
|
||||||
|
echo 'constexpr char tellertoml[]=R"('
|
||||||
|
cat teller.conf
|
||||||
|
echo ')";'
|
||||||
|
|
||||||
|
echo 'constexpr char trackerstoml[]=R"('
|
||||||
|
cat trackers.conf
|
||||||
|
echo ')";'
|
||||||
|
) > configs.hh
|
199
teller.cc
199
teller.cc
@ -5,57 +5,190 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <pcaudiolib/audio.h>
|
#include <pcaudiolib/audio.h>
|
||||||
|
#include "ext/toml.hpp"
|
||||||
|
#include "lpmwrapper.hh"
|
||||||
|
#include "configs.hh"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
audio_object* ao;
|
|
||||||
|
|
||||||
|
struct TrackerConf
|
||||||
|
{
|
||||||
|
double freq{400};
|
||||||
|
double balance{0.5}; // 0 is left, 1 is right
|
||||||
|
std::atomic<int64_t> counter{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void playerThread(const TrackerConf* tcptr)
|
||||||
|
{
|
||||||
|
auto& counter = tcptr->counter;
|
||||||
|
audio_object* ao;
|
||||||
ao=create_audio_device_object(0, "teller", "");
|
ao=create_audio_device_object(0, "teller", "");
|
||||||
if(!ao) {
|
if(!ao) {
|
||||||
cerr<<"Unable to open audio file "<<endl;
|
cerr<<"Unable to open audio file "<<endl;
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = audio_object_open(ao, AUDIO_OBJECT_FORMAT_S16LE, 44100, 1);
|
int res = audio_object_open(ao, AUDIO_OBJECT_FORMAT_S16LE, 44100, 2);
|
||||||
if(res < 0) {
|
if(res < 0) {
|
||||||
cerr<<"Error opening audio: "<<audio_object_strerror(ao, res)<<endl;
|
cerr<<"Error opening audio: "<<audio_object_strerror(ao, res)<<endl;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::atomic<int64_t> counter = 0;
|
vector<int16_t> data;
|
||||||
auto player = [&]() {
|
int ourcounter=0;
|
||||||
vector<int16_t> data;
|
data.reserve(44100);
|
||||||
int ourcounter=0;
|
while(counter >= 0) {
|
||||||
data.reserve(44100);
|
data.clear();
|
||||||
while(counter >= 0) {
|
if(ourcounter < counter) {
|
||||||
data.clear();
|
for(int n=0; n < 250; ++n) {
|
||||||
if(ourcounter < counter) {
|
int16_t val = 20000 * sin((n/44100.0) * tcptr->freq * 2 * M_PI);
|
||||||
for(int n=0; n < 250; ++n) {
|
int16_t lval = tcptr->balance * val;
|
||||||
int16_t val = 20000 * sin((n/44100.0) * 500 * 2 * M_PI);
|
int16_t rval = (1.0-tcptr->balance) * val;
|
||||||
data.push_back(val);
|
|
||||||
}
|
data.push_back(lval);
|
||||||
ourcounter++;
|
data.push_back(rval);
|
||||||
if(counter - ourcounter > 1000)
|
|
||||||
ourcounter = counter;
|
|
||||||
}
|
}
|
||||||
else {
|
ourcounter++;
|
||||||
for(int n=0; n < 150; ++n) {
|
if(counter - ourcounter > 1000)
|
||||||
data.push_back(0);
|
ourcounter = counter;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
audio_object_write(ao, &data[0], data.size() * sizeof(decltype(data)::value_type));
|
|
||||||
// audio_object_flush(ao);
|
|
||||||
}
|
}
|
||||||
};
|
else {
|
||||||
|
for(int n=0; n < 150; ++n) {
|
||||||
|
data.push_back(0);
|
||||||
|
data.push_back(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
audio_object_write(ao, &data[0], data.size() * sizeof(decltype(data)::value_type));
|
||||||
|
// audio_object_flush(ao);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::thread athread(player);
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
toml::table conftbl, trackertbl;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
trackertbl = toml::parse_file("trackers.conf");
|
||||||
|
conftbl = toml::parse_file("teller.conf");
|
||||||
|
}
|
||||||
|
catch (const toml::parse_error& err)
|
||||||
|
{
|
||||||
|
std::cerr << "Could not read configuration files, using built-in defaults" <<endl;
|
||||||
|
trackertbl = toml::parse(trackerstoml);
|
||||||
|
conftbl = toml::parse(tellertoml);
|
||||||
|
}
|
||||||
|
|
||||||
|
map<string, TrackerConf> trackerdb;
|
||||||
|
auto tellerarr = conftbl.as_table();
|
||||||
|
for(const auto& t : *tellerarr) {
|
||||||
|
auto& entry = trackerdb[(string)t.first];
|
||||||
|
entry.balance = conftbl[t.first]["balance"].value_or(0.5);
|
||||||
|
entry.freq = conftbl[t.first]["freq"].value_or(500);
|
||||||
|
cout <<"Want to play sound for tracker "<<t.first<<", balance= "<<entry.balance<<" frequency = "<<entry.freq<<endl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
LPMWrapper trackspos, tracksneg;
|
||||||
|
|
||||||
|
auto tarr = trackertbl.as_table();
|
||||||
|
for(const auto& t : *tarr) {
|
||||||
|
cout<<"Defining tracker "<<t.first<<endl;
|
||||||
|
if(trackerdb.count((string)t.first)==0) {
|
||||||
|
cout<<"Skipping tracker "<<t.first<<", user doesn't want it"<<endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto trackerptr = &trackerdb[(string)t.first];
|
||||||
|
auto track = trackertbl[t.first]["positive"].as_array();
|
||||||
|
|
||||||
|
if(track) {
|
||||||
|
track->for_each([&trackspos, &trackerptr](auto&& el) {
|
||||||
|
if constexpr (toml::is_string<decltype(el)>) {
|
||||||
|
trackspos.insert(*el, (void*)trackerptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cout<<"Not array?"<<endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
track = trackertbl[t.first]["negative"].as_array();
|
||||||
|
if(track) {
|
||||||
|
track->for_each([&tracksneg, &trackerptr](auto&& el) {
|
||||||
|
if constexpr (toml::is_string<decltype(el)>) {
|
||||||
|
tracksneg.insert(*el, (void*)trackerptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cout<<"Negative "<<t.first<<" not array?"<<endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for(const auto& t : trackerdb) {
|
||||||
|
std::thread athread(playerThread, &t.second);
|
||||||
|
athread.detach();
|
||||||
|
}
|
||||||
string line;
|
string line;
|
||||||
while(getline(cin, line)) {
|
while(getline(cin, line)) {
|
||||||
counter++;
|
|
||||||
|
/*
|
||||||
|
22:42:25.323984 IP 13.81.0.219.29601 > 10.0.0.3.32902: tcp 1186
|
||||||
|
22:42:25.323997 IP 10.0.0.3.32902 > 13.81.0.219.29601: tcp 0
|
||||||
|
22:42:25.327216 b0:95:75:c3:68:92 > ff:ff:ff:ff:ff:ff, RRCP-0x25 query
|
||||||
|
|
||||||
|
16:53:11.082416 IP6 2603:8000:ae00:d301:5636:9bff:fe27:6af6.59394 > 2001:41f0:782d:1::2.29603: tcp 0
|
||||||
|
|
||||||
|
*/
|
||||||
|
if(line.find(" IP6 ") != string::npos) {
|
||||||
|
auto pos = line.find('>');
|
||||||
|
if(pos == string::npos)
|
||||||
|
continue;
|
||||||
|
auto pos2 = line.find('.', pos);
|
||||||
|
if(pos2 == string::npos) continue;
|
||||||
|
line.resize(pos2);
|
||||||
|
string ip = line.substr(pos+2, pos2 - pos - 2);
|
||||||
|
|
||||||
|
if(tracksneg.lookup(&line.at(pos+2))) {
|
||||||
|
cout<<ip<<" negative match"<<endl;
|
||||||
|
}
|
||||||
|
else if(auto fptr = trackspos.lookup(&line.at(pos+2))) {
|
||||||
|
cout<<ip<<" match!"<<endl;
|
||||||
|
((TrackerConf*)fptr)->counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto pos = line.find('>');
|
||||||
|
if(pos == string::npos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto pos2 = line.find('.', pos);
|
||||||
|
if(pos2 == string::npos) continue;
|
||||||
|
pos2 = line.find('.', pos2+1);
|
||||||
|
if(pos2 == string::npos) continue;
|
||||||
|
pos2 = line.find('.', pos2+1);
|
||||||
|
if(pos2 == string::npos) continue;
|
||||||
|
pos2 = line.find_first_of(".:", pos2+1);
|
||||||
|
if(pos2 == string::npos) continue;
|
||||||
|
|
||||||
|
line.resize(pos2);
|
||||||
|
string ip=line.substr(pos+2, pos2 - pos - 2);
|
||||||
|
// cout<<&line.at(pos+2)<<endl;
|
||||||
|
if(tracksneg.lookup(&line.at(pos+2))) {
|
||||||
|
cout<<ip<<" negative match"<<endl;
|
||||||
|
}
|
||||||
|
else if(auto fptr = trackspos.lookup(&line.at(pos+2))) {
|
||||||
|
cout<<ip<<" match!"<<endl;
|
||||||
|
((TrackerConf*)fptr)->counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
counter = -1;
|
|
||||||
athread.join();
|
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
|
11
teller.conf
Normal file
11
teller.conf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[google]
|
||||||
|
balance=0
|
||||||
|
|
||||||
|
[facebook]
|
||||||
|
balance=1
|
||||||
|
freq=1000
|
||||||
|
|
||||||
|
[unassorted]
|
||||||
|
balance=0.5
|
||||||
|
freq=1500
|
||||||
|
|
45
testrunner.cc
Normal file
45
testrunner.cc
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||||
|
#include "ext/doctest.h"
|
||||||
|
#include "lpmwrapper.hh"
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
TEST_CASE("basic test") {
|
||||||
|
LPMWrapper t;
|
||||||
|
void* ptr = (void*)1;
|
||||||
|
t.insert("127.0.0.1/32", ptr);
|
||||||
|
|
||||||
|
CHECK(t.lookup("127.0.0.1") == ptr);
|
||||||
|
CHECK(t.lookup("127.0.0.2") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("IPv6 test") {
|
||||||
|
LPMWrapper t;
|
||||||
|
void* ptr = (void*)1;
|
||||||
|
t.insert("::1", ptr);
|
||||||
|
|
||||||
|
CHECK(t.lookup("::1") == ptr);
|
||||||
|
CHECK(t.lookup("::2") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("Mixed test") {
|
||||||
|
LPMWrapper t;
|
||||||
|
void* ptr = (void*)1;
|
||||||
|
t.insert("::1", ptr);
|
||||||
|
|
||||||
|
ptr = (void*)2;
|
||||||
|
t.insert("192.168.0.0/16", ptr);
|
||||||
|
|
||||||
|
|
||||||
|
CHECK(t.lookup("::1") == (void*)1);
|
||||||
|
CHECK(t.lookup("192.168.1.1") == (void*)2);
|
||||||
|
CHECK(t.lookup("192.168.255.255") == (void*)2);
|
||||||
|
CHECK(t.lookup("10.0.0.1") == 0);
|
||||||
|
CHECK(t.lookup("172.16.2.3") == 0);
|
||||||
|
CHECK(t.lookup("1.0.0.0") == 0);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
1040
trackers.conf
Normal file
1040
trackers.conf
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user