├── www ├── 192.168.3.2 ├── myip.vanheusden.com ├── default │ ├── phpinfo.php │ ├── .well-known │ │ ├── openpgpkey │ │ │ ├── vanheusden.com │ │ │ │ ├── policy │ │ │ │ └── hu │ │ │ │ │ └── dizb37aqa5h4skgu7jf1xjr4q71w4paq │ │ │ └── hackerspace-gouda.nl │ │ │ │ ├── policy │ │ │ │ └── hu │ │ │ │ └── mg6owx9w8c3ejg3tu31f4tha5n17d4rj │ │ └── security.txt │ ├── test.php │ ├── counter.php │ └── key.txt ├── hackerspace-gouda.nl └── www.hackerspace-gouda.nl │ ├── key.txt │ ├── .well-known │ ├── counter.php │ ├── favicon.ico │ └── index.html ├── Makefile ├── font.h ├── go.sh ├── my_ip.wav ├── test-node-001-stop.sh ├── test-node-002-stop.sh ├── .github └── FUNDING.yml ├── echo.h ├── sctp_crc32c.h ├── tsan.sup ├── mynetperf.h ├── tty.h ├── vpn-go.sh ├── run-test-node-001.sh ├── run-test-node-002.sh ├── test-node-001-go.sh ├── test-node-002-go.sh ├── go-tnc.sh ├── scapy-tcp.py ├── scapy-ip.py ├── scapy-udp-ntp.py ├── mqtt.h ├── nrpe.h ├── proc.h ├── irc.h ├── vnc.h ├── http.h ├── rommel.py ├── stats_utils.h ├── icmp.cpp ├── .travis.yml ├── fifo_stats.cpp ├── hash.h ├── .lgtm.yml ├── .gitignore ├── graphviz.h ├── duration_events.h ├── fifo_stats.h ├── time.h ├── net.h ├── tcp_udp_fw.h ├── icmp.h ├── socks_proxy.h ├── tcp_udp_fw.cpp ├── syslog.h ├── duration_events.cpp ├── mdns.h ├── str.h ├── pstream.h ├── icmp4.h ├── ndp.h ├── stats_tracker.h ├── utils.h ├── log.h ├── ud.h ├── phys_slip.h ├── phys_ppp.h ├── phys_sctp_udp.h ├── graphviz.cpp ├── myipnetstat.cpp ├── application.h ├── buffer_out.h ├── verify-snmp └── tester.py ├── phys_promiscuous.h ├── ndp.cpp ├── arp.h ├── ntp.h ├── phys_tap.h ├── syslog.cpp ├── transport_layer.h ├── buffer_in.h ├── cert.crt ├── phys_vpn_insertion_point.h ├── lldp.h ├── network_layer.cpp ├── stats_utils.cpp ├── address_cache.h ├── stats.h ├── packet.cpp ├── ipv6.h ├── dns.h ├── udp.h ├── vpn.h ├── snmprommel.py ├── any_addr.h ├── phys_kiss.h ├── my-key.key ├── icmp6.h ├── mac_resolver.h ├── session.cpp ├── network_layer.h ├── tty.cpp ├── snmp.h ├── hash.cpp ├── ipv4.h ├── myipnetstat.py ├── vpn.cfg ├── kiss-tnc-pty-server.cfg ├── packet.h ├── transport_layer.cpp ├── kiss-tnc-tcp-client.cfg ├── mqtt_client.h ├── kiss-tnc-tcp-server.cfg ├── session.h ├── router.cfg ├── time.cpp ├── README.md ├── stats_tracker.cpp ├── snmp_elem.h ├── proc.cpp ├── phys_gen_ppp.h ├── log.cpp ├── buffer_out.cpp ├── phys.h ├── snmp_data.h ├── test-node-001.cfg ├── test-node-002.cfg ├── phys_vpn_insertion_point.cpp ├── str.cpp ├── net.cpp ├── echo.cpp ├── ax25.h ├── buffer_in.cpp ├── netverify.py ├── router.h ├── test-http.py ├── stats.cpp ├── lldp.cpp ├── sip.h ├── example.cfg ├── phys_ppp.cpp ├── sctp.h ├── mynetperf-client.py └── fifo.h /www/192.168.3.2: -------------------------------------------------------------------------------- 1 | default/ -------------------------------------------------------------------------------- /www/myip.vanheusden.com: -------------------------------------------------------------------------------- 1 | default/ -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | (cd build/ && make -j 4) 3 | -------------------------------------------------------------------------------- /font.h: -------------------------------------------------------------------------------- 1 | extern uint8_t font_8x8[128][8][8]; 2 | -------------------------------------------------------------------------------- /www/default/phpinfo.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /www/hackerspace-gouda.nl: -------------------------------------------------------------------------------- 1 | www.hackerspace-gouda.nl/ -------------------------------------------------------------------------------- /www/www.hackerspace-gouda.nl/key.txt: -------------------------------------------------------------------------------- 1 | ../default/key.txt -------------------------------------------------------------------------------- /www/www.hackerspace-gouda.nl/.well-known: -------------------------------------------------------------------------------- 1 | ../default/.well-known/ -------------------------------------------------------------------------------- /www/www.hackerspace-gouda.nl/counter.php: -------------------------------------------------------------------------------- 1 | ../default/counter.php -------------------------------------------------------------------------------- /go.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | /usr/sbin/ifconfig myip 192.168.3.1 4 | -------------------------------------------------------------------------------- /my_ip.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/folkertvanheusden/MyIP/HEAD/my_ip.wav -------------------------------------------------------------------------------- /test-node-001-stop.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | /usr/bin/pkill -9 kissattach 4 | -------------------------------------------------------------------------------- /test-node-002-stop.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | /usr/bin/pkill -9 kissattach 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [folkertvanheusden] 2 | patreon: folkertvanheusden 3 | -------------------------------------------------------------------------------- /echo.h: -------------------------------------------------------------------------------- 1 | #include "application.h" 2 | 3 | 4 | port_handler_t echo_get_handler(); 5 | -------------------------------------------------------------------------------- /sctp_crc32c.h: -------------------------------------------------------------------------------- 1 | uint32_t generate_crc32c(const uint8_t *const buffer, const size_t length); 2 | -------------------------------------------------------------------------------- /tsan.sup: -------------------------------------------------------------------------------- 1 | race:frame_buffer_thread 2 | race:calculate_fb_update 3 | race:stats_inc_counter 4 | -------------------------------------------------------------------------------- /mynetperf.h: -------------------------------------------------------------------------------- 1 | #include "application.h" 2 | 3 | 4 | port_handler_t mynetperf_get_handler(); 5 | -------------------------------------------------------------------------------- /tty.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | int open_tty(const std::string & dev_name, const int bps); 5 | -------------------------------------------------------------------------------- /vpn-go.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | /usr/sbin/brctl addif br0 myip 4 | 5 | /usr/sbin/ifconfig myip up 6 | -------------------------------------------------------------------------------- /www/default/.well-known/openpgpkey/vanheusden.com/policy: -------------------------------------------------------------------------------- 1 | # Policy flags for domain vanheusden.com 2 | -------------------------------------------------------------------------------- /run-test-node-001.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | sudo ./build/myip -c test-node-001.cfg -d test-node-001.dot 4 | -------------------------------------------------------------------------------- /run-test-node-002.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | sudo ./build/myip -c test-node-002.cfg -d test-node-002.dot 4 | -------------------------------------------------------------------------------- /www/default/.well-known/openpgpkey/hackerspace-gouda.nl/policy: -------------------------------------------------------------------------------- 1 | # Policy flags for domain hackerspace-gouda.nl 2 | -------------------------------------------------------------------------------- /test-node-001-go.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | /usr/sbin/kissattach `/usr/bin/readlink /tmp/kisstnc.lnk` ax0 192.168.100.1 4 | -------------------------------------------------------------------------------- /test-node-002-go.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | /usr/sbin/kissattach `/usr/bin/readlink /tmp/kisstnc.lnk` ax0 192.168.100.4 4 | -------------------------------------------------------------------------------- /go-tnc.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | /usr/sbin/kissattach /tmp/tnc.lnk ax0 192.168.33.20 4 | /usr/sbin/kissattach /tmp/tnc2.lnk ax1 192.168.32.20 5 | 6 | exit 0 7 | -------------------------------------------------------------------------------- /scapy-tcp.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | from scapy.all import * 4 | 5 | test = Ether()/IP(dst='192.168.3.2')/fuzz(TCP()) 6 | 7 | while True: 8 | sendp(test, iface="myip") 9 | -------------------------------------------------------------------------------- /scapy-ip.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | from scapy.all import * 4 | 5 | test = Ether()/fuzz(IP(dst='192.168.3.2'))/fuzz(TCP()) 6 | 7 | while True: 8 | sendp(test, iface="myip") 9 | -------------------------------------------------------------------------------- /scapy-udp-ntp.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | from scapy.all import * 4 | 5 | test = Ether()/IP(dst='192.168.3.2')/fuzz(UDP()/NTP()) 6 | 7 | while True: 8 | sendp(test, iface="myip") 9 | -------------------------------------------------------------------------------- /mqtt.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #include "tcp.h" 3 | #include "stats.h" 4 | 5 | port_handler_t mqtt_get_handler(stats *const s); 6 | -------------------------------------------------------------------------------- /nrpe.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | 3 | #include "stats.h" 4 | #include "tcp.h" 5 | 6 | port_handler_t nrpe_get_handler(stats *const s); 7 | -------------------------------------------------------------------------------- /www/default/.well-known/openpgpkey/vanheusden.com/hu/dizb37aqa5h4skgu7jf1xjr4q71w4paq: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/folkertvanheusden/MyIP/HEAD/www/default/.well-known/openpgpkey/vanheusden.com/hu/dizb37aqa5h4skgu7jf1xjr4q71w4paq -------------------------------------------------------------------------------- /proc.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | std::tuple exec_with_pipe(const std::string & command, const std::string & dir, const std::vector & envs); 6 | void run(const std::string & what); 7 | -------------------------------------------------------------------------------- /www/default/.well-known/openpgpkey/hackerspace-gouda.nl/hu/mg6owx9w8c3ejg3tu31f4tha5n17d4rj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/folkertvanheusden/MyIP/HEAD/www/default/.well-known/openpgpkey/hackerspace-gouda.nl/hu/mg6owx9w8c3ejg3tu31f4tha5n17d4rj -------------------------------------------------------------------------------- /irc.h: -------------------------------------------------------------------------------- 1 | // (C) 2023 by folkert van heusden , released under Apache License v2.0 2 | 3 | #include "stats.h" 4 | #include "tcp.h" 5 | 6 | 7 | port_handler_t irc_get_handler(stats *const s, const std::string & local_host_in); 8 | -------------------------------------------------------------------------------- /www/default/test.php: -------------------------------------------------------------------------------- 1 | 9 |
10 | -------------------------------------------------------------------------------- /vnc.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2023 by folkert van heusden , released under Apache License v2.0 2 | 3 | #include "tcp.h" 4 | #include "stats.h" 5 | 6 | 7 | port_handler_t vnc_get_handler(stats *const s); 8 | 9 | void vnc_set_mqtt_client(mqtt_client *const mc); 10 | -------------------------------------------------------------------------------- /http.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | 3 | #include "application.h" 4 | #include "stats.h" 5 | 6 | 7 | port_handler_t http_get_handler(stats *const s, const std::string & web_root, const std::string & log_file, const bool is_https, const std::string & php_cgi); 8 | -------------------------------------------------------------------------------- /rommel.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | import random 4 | import socket 5 | 6 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 7 | 8 | while True: 9 | n = random.randint(1, 1500) 10 | 11 | out = bytes([random.getrandbits(8) for _ in range(0, n)]) 12 | 13 | s.sendto(out, ('myip.vanheusden.com', 161)) 14 | -------------------------------------------------------------------------------- /stats_utils.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #include 3 | #include 4 | 5 | #include "fifo_stats.h" 6 | 7 | 8 | std::string stats_to_json(const uint8_t *const p, const std::vector > & fs, const int size); 9 | -------------------------------------------------------------------------------- /icmp.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #include 3 | 4 | #include "icmp.h" 5 | #include "ipv4.h" 6 | #include "log.h" 7 | #include "time.h" 8 | #include "utils.h" 9 | 10 | 11 | icmp::icmp(stats *const s) : transport_layer(s, "icmp") 12 | { 13 | } 14 | 15 | icmp::~icmp() 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | dist: jammy 4 | 5 | before_install: 6 | - sudo apt-get -y install libiniparser-dev libsndfile1-dev libspeex-dev libsamplerate0-dev libconfig++-dev libjansson-dev libbearssl-dev libbsd-dev 7 | 8 | compiler: 9 | - clang 10 | 11 | before_script: 12 | - mkdir build 13 | - cd build 14 | - cmake .. 15 | 16 | script: 17 | - make 18 | -------------------------------------------------------------------------------- /fifo_stats.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2022 by folkert van heusden , released under Apache License v2.0 2 | #include "fifo_stats.h" 3 | 4 | fifo_stats::fifo_stats(const int range_max) 5 | { 6 | divider = (range_max + 1) / up_size; 7 | } 8 | 9 | fifo_stats::~fifo_stats() 10 | { 11 | } 12 | 13 | void fifo_stats::count(const int value) 14 | { 15 | counters[value / divider]++; 16 | } 17 | -------------------------------------------------------------------------------- /hash.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | uint64_t MurmurHash64A(const void *const key, const int len, const uint64_t seed); 7 | 8 | void md5bin(const uint8_t *const in, const size_t len, uint8_t *const h_out); 9 | std::string md5hex(const std::string & in); 10 | 11 | uint32_t crc32(const uint8_t *const data, const size_t n_data, const uint32_t polynomial); 12 | -------------------------------------------------------------------------------- /.lgtm.yml: -------------------------------------------------------------------------------- 1 | extraction: 2 | cpp: 3 | prepare: 4 | packages: 5 | - libbsd-dev 6 | - libconfig++-dev 7 | - libsndfile1-dev 8 | - libspeex-dev 9 | - libsamplerate0-dev 10 | configure: 11 | command: 12 | - mkdir _lgtm_build_dir 13 | - cd _lgtm_build_dir 14 | - cmake -DBUILD_GTEST=OFF -DINSTALL_GTEST=OFF .. 15 | index: 16 | build_command: 17 | - cd _lgtm_build_dir 18 | - make 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | *.pcap 35 | *.wav 36 | 37 | build 38 | tests 39 | work 40 | -------------------------------------------------------------------------------- /graphviz.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | class graphviz 6 | { 7 | private: 8 | const std::string filename; 9 | std::set > connections; 10 | std::set > nodes; 11 | 12 | public: 13 | graphviz(const std::string & filename); 14 | ~graphviz(); 15 | 16 | std::string add_node(const std::string & name, const std::string & meta); 17 | void add_connection(const std::string & from, const std::string & to); 18 | }; 19 | -------------------------------------------------------------------------------- /duration_events.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | class duration_events 11 | { 12 | private: 13 | mutable std::mutex lock; 14 | // duration, timestamp 15 | std::vector > events; 16 | const std::string name; 17 | const size_t max_size; 18 | 19 | public: 20 | duration_events(const std::string name, const int max_size); 21 | 22 | void insert(const uint64_t duration); 23 | 24 | auto get() const; 25 | }; 26 | -------------------------------------------------------------------------------- /fifo_stats.h: -------------------------------------------------------------------------------- 1 | // (C) 2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | #include 4 | 5 | static constexpr int up_size = 100; 6 | 7 | class fifo_stats 8 | { 9 | private: 10 | uint64_t counters[up_size] { 0 }; 11 | int divider { 1 }; 12 | 13 | public: 14 | fifo_stats(const int range_max); 15 | virtual ~fifo_stats(); 16 | 17 | void count(const int value); 18 | 19 | int get_size() const { return up_size; }; 20 | 21 | uint64_t get_counter(const int idx) const { return counters[idx]; } 22 | }; 23 | -------------------------------------------------------------------------------- /time.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | uint64_t get_us(); 9 | uint64_t get_ms(); 10 | uint32_t ms_since_midnight(); 11 | 12 | void myusleep(uint64_t us); 13 | 14 | class interruptable_sleep 15 | { 16 | private: 17 | std::mutex lock; 18 | std::condition_variable cv; 19 | bool stop { false }; 20 | 21 | public: 22 | interruptable_sleep(); 23 | 24 | void signal_stop(); 25 | 26 | // returns true when stop is set 27 | bool sleep(const uint32_t ms); 28 | }; 29 | -------------------------------------------------------------------------------- /net.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "any_addr.h" 6 | 7 | 8 | void swap_mac(uint8_t *a, uint8_t *b); 9 | void swap_ipv4(uint8_t *a, uint8_t *b); 10 | 11 | int create_datagram_socket(const int port); 12 | 13 | std::optional get_host_as_text(struct sockaddr *const a); 14 | 15 | bool check_subnet(const any_addr & addr, const any_addr & network, const int cidr); 16 | bool check_subnet(const any_addr & addr, const any_addr & network, const uint8_t netmask[4]); 17 | 18 | any_addr gen_opponent_mac(const any_addr & my_mac); 19 | -------------------------------------------------------------------------------- /tcp_udp_fw.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | #include 4 | 5 | #include "any_addr.h" 6 | #include "stats.h" 7 | #include "types.h" 8 | 9 | 10 | class packet; 11 | class udp; 12 | 13 | class tcp_udp_fw 14 | { 15 | private: 16 | uint64_t *fw_n_dropped { nullptr }; 17 | 18 | public: 19 | tcp_udp_fw(stats *const s, udp *const u); 20 | virtual ~tcp_udp_fw(); 21 | 22 | void input(const any_addr & src_ip, int src_port, const any_addr & dst_ip, int dst_port, packet *p, session_data *const pd); 23 | }; 24 | -------------------------------------------------------------------------------- /icmp.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include "any_addr.h" 5 | #include "transport_layer.h" 6 | #include "stats.h" 7 | 8 | 9 | class icmp : public transport_layer 10 | { 11 | public: 12 | icmp(stats *const s); 13 | virtual ~icmp(); 14 | 15 | virtual void send_destination_port_unreachable(const any_addr & dst_ip, const any_addr & src_ip, const packet *const p) const = 0; 16 | 17 | virtual void operator()() override = 0; 18 | 19 | virtual void send_ttl_exceeded(const packet *const pkt) const = 0; 20 | }; 21 | -------------------------------------------------------------------------------- /socks_proxy.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "dns.h" 5 | #include "tcp.h" 6 | 7 | class socks_proxy 8 | { 9 | private: 10 | std::thread *th { nullptr }; 11 | std::atomic_bool stop_flag { false }; 12 | tcp *const t { nullptr }; 13 | dns *dns_ { nullptr }; 14 | 15 | int fd { -1 }; 16 | 17 | public: 18 | socks_proxy(const std::string & interface, const int port, tcp *const t); 19 | virtual ~socks_proxy(); 20 | 21 | void ask_to_stop() { 22 | stop_flag = true; 23 | } 24 | 25 | void register_dns(dns *const dns_) { this->dns_ = dns_; } 26 | 27 | void operator()(); 28 | }; 29 | -------------------------------------------------------------------------------- /tcp_udp_fw.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2020 by folkert van heusden , released under Apache License v2.0 2 | #include 3 | #include 4 | 5 | #include "tcp_udp_fw.h" 6 | #include "udp.h" 7 | 8 | tcp_udp_fw::tcp_udp_fw(stats *const s, udp *const u) 9 | { 10 | // 1.3.6.1.4.1.57850.1.10: firewall 11 | fw_n_dropped = s->register_stat("fw_n_dropped", "1.3.6.1.4.1.57850.1.10.1"); 12 | } 13 | 14 | tcp_udp_fw::~tcp_udp_fw() 15 | { 16 | } 17 | 18 | void tcp_udp_fw::input(const any_addr & src_ip, int src_port, const any_addr & dst_ip, int dst_port, packet *p, session_data *const pd) 19 | { 20 | // silently drop 21 | stats_inc_counter(fw_n_dropped); 22 | } 23 | -------------------------------------------------------------------------------- /syslog.h: -------------------------------------------------------------------------------- 1 | // (C) 2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "any_addr.h" 8 | #include "application.h" 9 | #include "stats.h" 10 | 11 | class packet; 12 | class udp; 13 | 14 | class syslog_srv : public application 15 | { 16 | private: 17 | uint64_t *syslog_srv_requests { nullptr }; 18 | 19 | public: 20 | syslog_srv(stats *const s); 21 | syslog_srv(const syslog_srv &) = delete; 22 | virtual ~syslog_srv(); 23 | 24 | void input(const any_addr & src_ip, int src_port, const any_addr & dst_ip, int dst_port, packet *p, session_data *const pd); 25 | }; 26 | -------------------------------------------------------------------------------- /duration_events.cpp: -------------------------------------------------------------------------------- 1 | #include "duration_events.h" 2 | #include "log.h" 3 | #include "time.h" 4 | 5 | 6 | duration_events::duration_events(const std::string name, const int max_size) : name(name), max_size(max_size) 7 | { 8 | events.resize(max_size); 9 | } 10 | 11 | void duration_events::insert(const uint64_t duration) 12 | { 13 | std::unique_lock lck(lock); 14 | 15 | if (events.at(0).first < duration) { 16 | DOLOG(ll_info, "duration_events(%s): %zu\n", name.c_str(), size_t(duration)); 17 | events.insert(events.begin(), { duration, get_us() }); 18 | 19 | events.resize(max_size); 20 | } 21 | } 22 | 23 | auto duration_events::get() const 24 | { 25 | std::unique_lock lck(lock); 26 | 27 | return events; 28 | } 29 | -------------------------------------------------------------------------------- /mdns.h: -------------------------------------------------------------------------------- 1 | // (C) 2022 by folkert van heusden , released under Apache License v2.0 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "application.h" 11 | #include "udp.h" 12 | 13 | 14 | class mdns : public application 15 | { 16 | private: 17 | struct entry { 18 | udp *interface; 19 | int port; 20 | std::string hostname; 21 | }; 22 | 23 | std::vector protocols; 24 | std::mutex lock; 25 | 26 | std::thread * th { nullptr }; 27 | 28 | public: 29 | mdns(); 30 | mdns(const mdns &) = delete; 31 | virtual ~mdns(); 32 | 33 | void add_protocol(udp *const u, const int port, const std::string & host); 34 | 35 | void operator()(); 36 | }; 37 | -------------------------------------------------------------------------------- /str.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | std::string myformat(const char *const fmt, ...); 9 | std::vector split(std::string in, std::string splitter); 10 | std::string replace(std::string target, const std::string & what, const std::string & by_what); 11 | std::string bin_to_text(const uint8_t *p, const size_t len, const bool prefer_ascii); 12 | std::string merge(const std::vector & in, const std::string & seperator); 13 | std::string str_tolower(std::string s); 14 | std::optional find_header(const std::vector *const lines, const std::string & key, const std::string & seperator); 15 | -------------------------------------------------------------------------------- /pstream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "session.h" 10 | 11 | 12 | class pstream 13 | { 14 | protected: 15 | mutable std::shared_mutex sessions_lock; 16 | // the key is an 'internal id' 17 | std::map sessions; 18 | 19 | public: 20 | pstream() { } 21 | virtual ~pstream() { } 22 | 23 | virtual bool send_data(session *const s, const uint8_t *const data, const size_t len) = 0; 24 | 25 | virtual void end_session(session *const ts) = 0; 26 | 27 | virtual json_t *get_state_json(session *const ts) = 0; 28 | 29 | auto get_sessions_locked() const { sessions_lock.lock_shared(); return &sessions; } 30 | 31 | void sessions_unlock() { sessions_lock.unlock_shared(); } 32 | }; 33 | -------------------------------------------------------------------------------- /icmp4.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include "any_addr.h" 5 | #include "icmp.h" 6 | #include "stats.h" 7 | 8 | class icmp4 : public icmp 9 | { 10 | private: 11 | uint64_t *icmp_requests { nullptr }, *icmp_req_ping { nullptr }; 12 | uint64_t *icmp_transmit { nullptr }; 13 | 14 | void send_packet(const any_addr & dst_ip, const any_addr & src_ip, const uint8_t type, const uint8_t code, const packet *const p) const; 15 | 16 | public: 17 | icmp4(stats *const s, const int n_threads); 18 | virtual ~icmp4(); 19 | 20 | void send_destination_port_unreachable(const any_addr & dst_ip, const any_addr & src_ip, const packet *const p) const override; 21 | 22 | void send_ttl_exceeded(const packet *const pkt) const override; 23 | 24 | void operator()() override; 25 | }; 26 | -------------------------------------------------------------------------------- /ndp.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2023 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "any_addr.h" 7 | #include "mac_resolver.h" 8 | #include "stats.h" 9 | 10 | 11 | class icmp6; 12 | 13 | class ndp : public mac_resolver 14 | { 15 | private: 16 | icmp6 *icmp6_ { nullptr }; 17 | 18 | uint64_t *ndp_cache_req { nullptr }; 19 | uint64_t *ndp_cache_hit { nullptr }; 20 | 21 | bool send_request(const any_addr & ip, const any_addr::addr_family af) override; 22 | 23 | std::optional check_special_ip_addresses(const any_addr & ip, const any_addr::addr_family family) override; 24 | 25 | public: 26 | ndp(stats *const s); 27 | virtual ~ndp(); 28 | 29 | void register_icmp6(icmp6 *const icmp6_) { this->icmp6_ = icmp6_; } 30 | 31 | void operator()() override; 32 | }; 33 | -------------------------------------------------------------------------------- /stats_tracker.h: -------------------------------------------------------------------------------- 1 | // (C) 2017-2022 by folkert van heusden, released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | class stats_tracker 14 | { 15 | private: 16 | int prev_slot_ru { -1 }; 17 | uint64_t prev_ru_ts { 0 }; 18 | 19 | struct rusage latest_ru { 0 }; 20 | struct rusage prev_ru { 0 }; 21 | 22 | double cpu_stats[5] { 0. }; 23 | 24 | std::thread *th { nullptr }; 25 | 26 | std::condition_variable cv_stop; 27 | mutable std::mutex m; 28 | bool cv_stop_notify { false }; 29 | 30 | public: 31 | stats_tracker(); 32 | virtual ~stats_tracker(); 33 | 34 | void operator()(); 35 | 36 | double get_cpu_usage() const; 37 | }; 38 | 39 | extern stats_tracker *st; 40 | -------------------------------------------------------------------------------- /utils.h: -------------------------------------------------------------------------------- 1 | // (C) 2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | uint8_t *duplicate(const uint8_t *const in, const size_t size); 9 | 10 | void get_random(uint8_t *tgt, size_t n); 11 | 12 | uint8_t * get_from_buffer(uint8_t **p, size_t *len, size_t get_len); 13 | 14 | void set_thread_name(std::string name); 15 | std::string get_thread_name(); 16 | bool file_exists(const std::string & file, size_t *const file_size = nullptr); 17 | 18 | void error_exit(const bool se, const char *format, ...); 19 | 20 | std::optional load_text_file(const std::string & filename); 21 | 22 | ssize_t READ(int fd, uint8_t *whereto, size_t len); 23 | ssize_t WRITE(int fd, const uint8_t *wherefrom, size_t len); 24 | 25 | int determine_value_size(uint32_t n); 26 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "str.h" 6 | 7 | 8 | typedef enum { ll_debug, ll_info, ll_warning, ll_error } log_level_t; 9 | 10 | void setlog(const char *lf, const log_level_t ll_file, const log_level_t ll_screen); 11 | void setloguid(const int uid, const int gid); 12 | void closelog(); 13 | void dolog(const log_level_t ll, const char *fmt, ...); 14 | 15 | #define DOLOG(ll, fmt, ...) do { \ 16 | extern log_level_t log_level_file, log_level_screen; \ 17 | \ 18 | if (ll >= log_level_file || ll >= log_level_screen) \ 19 | dolog(ll, fmt, ##__VA_ARGS__); \ 20 | } while(0) 21 | 22 | #define CDOLOG(ll, context, fmt, ...) do { \ 23 | extern log_level_t log_level_file, log_level_screen; \ 24 | \ 25 | if (ll >= log_level_file || ll >= log_level_screen) { \ 26 | std::string __log_temp = myformat(fmt, ##__VA_ARGS__);\ 27 | dolog(ll, "%s %s", context, __log_temp.c_str()); \ 28 | } \ 29 | } while(0) 30 | -------------------------------------------------------------------------------- /ud.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "tcp.h" 6 | 7 | 8 | class ud_stats 9 | { 10 | private: 11 | int fd { -1 }; 12 | std::vector stream_session_handlers; 13 | 14 | std::vector *const devs { nullptr }; 15 | 16 | std::thread *th { nullptr }; 17 | std::atomic_bool stop_flag { false }; 18 | 19 | void handler (const int cfd); 20 | 21 | void emit_devices (const int cfd); 22 | void emit_sessions(const int cfd); 23 | 24 | void handle_pcap (const int cfd, const std::string & dev, const bool open); 25 | 26 | void emit_arp (const int cfd, const std::string & dev_name); 27 | 28 | public: 29 | ud_stats(const std::vector & stream_session_handlers, std::vector *const devs, const std::string & socket_path); 30 | virtual ~ud_stats(); 31 | 32 | void operator()(); 33 | }; 34 | -------------------------------------------------------------------------------- /phys_slip.h: -------------------------------------------------------------------------------- 1 | // (C) 2023 by folkert van heusden , released under Apache License v2.0 2 | 3 | #pragma once 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "any_addr.h" 11 | #include "phys.h" 12 | #include "network_layer.h" 13 | #include "stats.h" 14 | 15 | class phys_slip : public phys 16 | { 17 | protected: 18 | int fd { -1 }; 19 | 20 | public: 21 | phys_slip(const size_t dev_index, stats *const s, const std::string & dev_name, const int bps, const any_addr & my_mac, router *const r); 22 | phys_slip(const phys_slip &) = delete; 23 | virtual ~phys_slip(); 24 | 25 | void start() override; 26 | 27 | bool transmit_packet(const any_addr & dest_mac, const any_addr & src_mac, const uint16_t ether_type, const uint8_t *payload, const size_t pl_size) override; 28 | 29 | any_addr::addr_family get_phys_type() override { return any_addr::mac; } 30 | 31 | void operator()() override; 32 | }; 33 | -------------------------------------------------------------------------------- /phys_ppp.h: -------------------------------------------------------------------------------- 1 | // (C) 2022-2023 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "any_addr.h" 11 | #include "network_layer.h" 12 | #include "phys_gen_ppp.h" 13 | #include "stats.h" 14 | 15 | 16 | class phys_ppp : public phys_gen_ppp 17 | { 18 | private: 19 | std::mutex send_lock; 20 | 21 | int fd { -1 }; 22 | bool emulate_modem_xp { false }; 23 | 24 | protected: 25 | bool transmit_low(const std::vector & payload, const uint16_t protocol, const std::vector & ACCM, const bool not_ppp_meta) override; 26 | 27 | public: 28 | phys_ppp(const size_t dev_index, stats *const s, const std::string & dev_name, const int bps, const any_addr & my_mac, const bool emulate_modem_xp, const any_addr & opponent_address, router *const r); 29 | phys_ppp(const phys_ppp &) = delete; 30 | virtual ~phys_ppp(); 31 | 32 | void operator()() override; 33 | }; 34 | -------------------------------------------------------------------------------- /phys_sctp_udp.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2023 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "any_addr.h" 11 | #include "phys.h" 12 | #include "network_layer.h" 13 | #include "stats.h" 14 | 15 | 16 | class phys_sctp_udp : public phys 17 | { 18 | private: 19 | const any_addr my_addr; // IPv4 address matching the port 20 | int fd { -1 }; 21 | 22 | public: 23 | phys_sctp_udp(const size_t dev_index, stats *const s, const any_addr & my_mac, const any_addr & my_addr, const int port, router *const r); 24 | phys_sctp_udp(const phys_sctp_udp &) = delete; 25 | virtual ~phys_sctp_udp(); 26 | 27 | bool transmit_packet(const any_addr & dest_mac, const any_addr & src_mac, const uint16_t ether_type, const uint8_t *payload, const size_t pl_size) override; 28 | 29 | any_addr::addr_family get_phys_type() override { return any_addr::mac; } 30 | 31 | void operator()() override; 32 | }; 33 | -------------------------------------------------------------------------------- /graphviz.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "graphviz.h" 4 | #include "utils.h" 5 | 6 | 7 | graphviz::graphviz(const std::string & filename) : filename(filename) 8 | { 9 | } 10 | 11 | graphviz::~graphviz() 12 | { 13 | if (filename.empty() == false) { 14 | FILE *fh = fopen(filename.c_str(), "w"); 15 | if (!fh) 16 | error_exit(true, "Failed creating %s", filename.c_str()); 17 | 18 | fprintf(fh, "digraph {\n"); 19 | 20 | for(auto & node: nodes) 21 | fprintf(fh, "\t\"%s\" [label=\"%s\"]\n", node.first.c_str(), node.second.c_str()); 22 | 23 | for(auto & connection: connections) 24 | fprintf(fh, "\t\"%s\" -> \"%s\"\n", connection.first.c_str(), connection.second.c_str()); 25 | 26 | fprintf(fh, "}\n"); 27 | 28 | fclose(fh); 29 | } 30 | } 31 | 32 | std::string graphviz::add_node(const std::string & name, const std::string & meta) 33 | { 34 | nodes.insert({ name, meta }); 35 | 36 | return name; 37 | } 38 | 39 | void graphviz::add_connection(const std::string & from, const std::string & to) 40 | { 41 | connections.insert({ from, to }); 42 | } 43 | -------------------------------------------------------------------------------- /myipnetstat.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "utils.h" 9 | 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | int fd = socket(AF_UNIX, SOCK_STREAM, 0); 14 | if (fd == -1) 15 | error_exit(true, "Cannot create unix domain socket"); 16 | 17 | struct sockaddr_un remote { 0 }; 18 | 19 | remote.sun_family = AF_UNIX; 20 | strcpy(remote.sun_path, "/tmp/myipstats.sock"); 21 | 22 | int len = strlen(remote.sun_path) + sizeof(remote.sun_family); 23 | 24 | if (connect(fd, reinterpret_cast(&remote), len) == -1) 25 | error_exit(true, "Failed to connect"); 26 | 27 | char cmd[] = "sessions\n"; 28 | 29 | WRITE(fd, reinterpret_cast(cmd), sizeof(cmd) - 1); 30 | 31 | for(;;) { 32 | char buffer[4096] { 0 }; 33 | 34 | int rc = read(fd, buffer, (sizeof buffer) - 1); 35 | 36 | if (rc == 0 || rc == -1) 37 | break; 38 | 39 | printf("%s\n", buffer); 40 | } 41 | 42 | close(fd); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /application.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "buffer_in.h" 7 | #include "packet.h" 8 | #include "pstream.h" 9 | #include "session.h" 10 | #include "time.h" 11 | #include "types.h" 12 | 13 | 14 | typedef struct { 15 | std::function init; 16 | std::function new_session; 17 | std::function new_data; 18 | std::function session_closed_1; // please terminate 19 | std::function session_closed_2; // should be terminated, clean up 20 | std::function deinit; 21 | private_data *pd; 22 | } port_handler_t; 23 | 24 | class application 25 | { 26 | protected: 27 | interruptable_sleep stop_flag; 28 | 29 | private_data *const pd { nullptr }; 30 | 31 | public: 32 | application() { 33 | } 34 | 35 | virtual ~application() { 36 | ask_to_stop(); 37 | } 38 | 39 | void ask_to_stop() { 40 | stop_flag.signal_stop(); 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /buffer_out.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "any_addr.h" 6 | #include "buffer_in.h" 7 | 8 | 9 | class buffer_out 10 | { 11 | private: 12 | std::vector buffer; 13 | 14 | public: 15 | buffer_out(); 16 | virtual ~buffer_out(); 17 | 18 | void add_net_byte (const uint8_t b); 19 | void add_net_short(const uint16_t s); 20 | void add_net_long (const uint32_t l); 21 | 22 | // used by length fields 23 | size_t add_net_short(const uint16_t s, const ssize_t offset); 24 | size_t add_net_long (const uint32_t s, const ssize_t offset); 25 | 26 | void add_any_addr(const any_addr & a); 27 | 28 | void add_buffer_out(const buffer_out & o); 29 | void add_buffer_in ( buffer_in & i); 30 | 31 | void add_buffer(const uint8_t *const p, const size_t l); 32 | 33 | // pad to a multiple of m 34 | void add_padding(const int m); 35 | 36 | const std::vector & get_payload() const; 37 | 38 | bool compare(const buffer_in & b) const; 39 | 40 | size_t get_size() const; 41 | const uint8_t *get_content() const; 42 | }; 43 | -------------------------------------------------------------------------------- /verify-snmp/tester.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | from snmp_client import snmp_client 4 | import socket 5 | import sys 6 | 7 | target = sys.argv[1] 8 | 9 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 10 | 11 | request = bytearray(snmp_client.make_snmp_get_request(0, 'public', ['1.3.6.1.2.1.1.4.0', '1.3.6.1.2.1.1.5.0', '1.3.6.1.2.1.1.6.0'])) 12 | 13 | s.sendto(request, (target, 161)) 14 | 15 | reply = s.recvmsg(1600) 16 | payload = reply[0] 17 | 18 | # verify total length 19 | if payload[1] + 2 > len(payload): 20 | print('Total message size incorrect') 21 | 22 | offset = 2 23 | 24 | # verify version 25 | rc = snmp_client.get_snmp_integer(payload, offset) 26 | offset += rc[1] 27 | 28 | if rc[0] != 0: 29 | print(f'SNMP version unexpected ({rc[0]})') 30 | 31 | # verify community 32 | rc = snmp_client.get_snmp_octetstring(payload, offset) 33 | offset += rc[1] 34 | 35 | c = rc[0].decode('ascii') 36 | if c != 'public': 37 | print(f'Community unexpected ({c})') 38 | 39 | rc = snmp_client.get_pdu(payload, offset) 40 | offset += rc[1] 41 | print(rc) 42 | 43 | s.close() 44 | -------------------------------------------------------------------------------- /phys_promiscuous.h: -------------------------------------------------------------------------------- 1 | // (C) 2023 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "any_addr.h" 10 | #include "duration_events.h" 11 | #include "phys.h" 12 | #include "phys_kiss.h" 13 | #include "network_layer.h" 14 | #include "stats.h" 15 | 16 | 17 | class phys_promiscuous : public phys 18 | { 19 | private: 20 | int fd { -1 }; 21 | int ifr_index { -1 }; 22 | 23 | duration_events transmit_packet_de { "transmit packet", 8 }; 24 | 25 | public: 26 | phys_promiscuous(const size_t dev_index, stats *const s, const std::string & dev_name, router *const r); 27 | phys_promiscuous(const phys_promiscuous &) = delete; 28 | virtual ~phys_promiscuous(); 29 | 30 | bool transmit_packet(const any_addr & dest_mac, const any_addr & src_mac, const uint16_t ether_type, const uint8_t *payload, const size_t pl_size) override; 31 | 32 | any_addr::addr_family get_phys_type() override { return any_addr::mac; } 33 | 34 | void operator()() override; 35 | }; 36 | -------------------------------------------------------------------------------- /www/default/counter.php: -------------------------------------------------------------------------------- 1 | prepare($q1); 29 | $stmt->bind_param('sii', $uuid, $count, $count); 30 | $stmt->execute(); 31 | 32 | $q2 = 'INSERT INTO hits_history(ts, cookie) VALUES(NOW(), ?)'; 33 | 34 | $stmt = $connection->prepare($q2); 35 | $stmt->bind_param('s', $uuid); 36 | $stmt->execute(); 37 | 38 | $q3 = 'SELECT COUNT(*) AS n FROM hits'; 39 | 40 | $res = $connection->query($q3); 41 | $row = $res->fetch_assoc(); 42 | 43 | print($row['n']); ?> 44 | -------------------------------------------------------------------------------- /ndp.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #include 3 | #include 4 | #include 5 | 6 | #include "any_addr.h" 7 | #include "icmp6.h" 8 | #include "ndp.h" 9 | #include "phys.h" 10 | 11 | 12 | ndp::ndp(stats *const s) : mac_resolver(s, nullptr) 13 | { 14 | // 1.3.6.1.4.1.57850.1.9: ndp 15 | ndp_cache_req = s->register_stat("ndp_cache_req", "1.3.6.1.4.1.57850.1.9.1"); 16 | ndp_cache_hit = s->register_stat("ndp_cache_hit", "1.3.6.1.4.1.57850.1.9.2"); 17 | } 18 | 19 | ndp::~ndp() 20 | { 21 | } 22 | 23 | void ndp::operator()() 24 | { 25 | } 26 | 27 | bool ndp::send_request(const any_addr & ip, const any_addr::addr_family af) 28 | { 29 | if (icmp6_) { 30 | icmp6_->send_packet_neighbor_solicitation(ip); 31 | 32 | return true; 33 | } 34 | 35 | DOLOG(ll_error, "ndp::send_request: no icmp6 instance available\n"); 36 | 37 | return false; 38 | } 39 | 40 | std::optional ndp::check_special_ip_addresses(const any_addr & ip, const any_addr::addr_family family) 41 | { 42 | return { }; 43 | } 44 | -------------------------------------------------------------------------------- /arp.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | #include "mac_resolver.h" 8 | #include "network_layer.h" 9 | #include "phys.h" 10 | #include "stats.h" 11 | 12 | 13 | typedef struct { 14 | uint64_t ts; 15 | any_addr addr; 16 | } arp_entry_t; 17 | 18 | class arp : public mac_resolver 19 | { 20 | private: 21 | const any_addr my_mac; 22 | const any_addr my_ip; 23 | 24 | uint64_t *arp_requests { nullptr }; 25 | uint64_t *arp_for_me { nullptr }; 26 | 27 | std::thread *arp_th { nullptr }; 28 | std::atomic_bool arp_stop_flag { false }; 29 | 30 | phys *const interface { nullptr }; 31 | 32 | bool send_request(const any_addr & ip, const any_addr::addr_family af) override; 33 | 34 | std::optional check_special_ip_addresses(const any_addr & ip, const any_addr::addr_family family) override; 35 | 36 | public: 37 | arp(stats *const s, phys *const interface, const any_addr & mymac, const any_addr & myip); 38 | virtual ~arp(); 39 | 40 | void operator()() override; 41 | }; 42 | -------------------------------------------------------------------------------- /ntp.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "any_addr.h" 8 | #include "application.h" 9 | #include "stats.h" 10 | 11 | class packet; 12 | class udp; 13 | 14 | class ntp : public application 15 | { 16 | private: 17 | udp *const u; 18 | 19 | const any_addr my_ip, upstream_ntp_server; 20 | 21 | const bool broadcast; 22 | 23 | std::thread *th { nullptr }; 24 | 25 | uint64_t *ntp_requests { nullptr }, *ntp_invalid { nullptr }, *ntp_time_req { nullptr }; 26 | uint64_t *ntp_t_req_v[8] { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; 27 | uint64_t *ntp_broadcast { nullptr }; 28 | 29 | public: 30 | ntp(stats *const s, udp *const u, const any_addr & my_ip, const any_addr & upstream_ntp_server, const bool broadcast); 31 | ntp(const ntp &) = delete; 32 | virtual ~ntp(); 33 | 34 | void input(const any_addr & src_ip, int src_port, const any_addr & dst_ip, int dst_port, packet *p, session_data *const pd); 35 | 36 | void operator()(); 37 | }; 38 | -------------------------------------------------------------------------------- /phys_tap.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2023 by folkert van heusden , released under Apache License v2.0 2 | 3 | #pragma once 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "any_addr.h" 10 | #include "phys.h" 11 | #include "network_layer.h" 12 | #include "stats.h" 13 | 14 | 15 | class phys_tap : public phys 16 | { 17 | private: 18 | int fd { -1 }; 19 | 20 | public: 21 | phys_tap(const size_t dev_index, stats *const s, const std::string & dev_name, const int uid, const int gid, const int mtu_size, router *const r); 22 | phys_tap(const phys_tap &) = delete; 23 | virtual ~phys_tap(); 24 | 25 | bool transmit_packet(const any_addr & dest_mac, const any_addr & src_mac, const uint16_t ether_type, const uint8_t *payload, const size_t pl_size) override; 26 | 27 | any_addr::addr_family get_phys_type() override { return any_addr::mac; } 28 | 29 | void operator()() override; 30 | }; 31 | 32 | bool process_ethernet_frame(const timespec & ts, const std::vector & buffer, std::map *const prot_map, router *const r, phys *const source_phys); 33 | -------------------------------------------------------------------------------- /syslog.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2020 by folkert van heusden , released under Apache License v2.0 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "log.h" 8 | #include "syslog.h" 9 | #include "udp.h" 10 | 11 | 12 | syslog_srv::syslog_srv(stats *const s) 13 | { 14 | // 1.3.6.1.4.1.57850.1.6: syslog 15 | syslog_srv_requests = s->register_stat("syslog_srv_requests", "1.3.6.1.4.1.57850.1.6.1"); 16 | } 17 | 18 | syslog_srv::~syslog_srv() 19 | { 20 | stop_flag.signal_stop(); 21 | } 22 | 23 | void syslog_srv::input(const any_addr & src_ip, int src_port, const any_addr & dst_ip, int dst_port, packet *p, session_data *const pd) 24 | { 25 | stats_inc_counter(syslog_srv_requests); 26 | 27 | auto pl = p->get_payload(); 28 | 29 | if (pl.second == 0) { 30 | DOLOG(ll_info, "SYSLOG: empty packet from [%s]:%u\n", src_ip.to_str().c_str(), src_port); 31 | return; 32 | } 33 | 34 | std::string pl_str = std::string(reinterpret_cast(pl.first), pl.second); 35 | 36 | DOLOG(ll_info, "SYSLOG: \"%s\" from [%s]:%d\n", pl_str.c_str(), src_ip.to_str().c_str(), src_port); 37 | } 38 | -------------------------------------------------------------------------------- /transport_layer.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "fifo.h" 11 | #include "packet.h" 12 | #include "network_layer.h" 13 | 14 | 15 | class ipv4; 16 | 17 | class transport_layer 18 | { 19 | protected: 20 | std::vector ths; 21 | std::atomic_bool stop_flag { false }; 22 | 23 | fifo *pkts { nullptr }; 24 | 25 | network_layer *idev { nullptr }; 26 | 27 | public: 28 | transport_layer(stats *const s, const std::string & stats_name); 29 | virtual ~transport_layer(); 30 | 31 | void ask_to_stop() { stop_flag = true; } 32 | 33 | void register_ip(network_layer *const p) { idev = p; } 34 | 35 | any_addr get_ip_address() const { return idev->get_addr(); } 36 | 37 | void queue_packet(packet *p); 38 | 39 | virtual void operator()() = 0; 40 | }; 41 | 42 | uint16_t tcp_udp_checksum(const any_addr & src_addr, const any_addr & dst_addr, const bool tcp, const uint8_t *const tcp_payload, const int len); 43 | -------------------------------------------------------------------------------- /buffer_in.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | class buffer_in 9 | { 10 | private: 11 | const uint8_t *p { nullptr }; 12 | int size { 0 }; 13 | mutable int o { 0 }; 14 | 15 | const uint8_t * get_pointer() const { return p; }; 16 | 17 | public: 18 | buffer_in(); 19 | buffer_in(const uint8_t *p, const int size); 20 | buffer_in(const buffer_in & b); 21 | virtual ~buffer_in(); 22 | 23 | uint8_t get_net_byte(); 24 | uint16_t get_net_short(); // 2 bytes 25 | uint32_t get_net_long(); // 4 bytes 26 | uint64_t get_net_long_long(); // 8 bytes 27 | float get_net_float(); 28 | double get_net_double(); 29 | const uint8_t * get_bytes(const int len) const; 30 | 31 | int get_size() const { return size; }; 32 | 33 | buffer_in get_segment(const int len); 34 | 35 | std::string get_string(const int len); 36 | 37 | void seek(const int len); 38 | 39 | bool end_reached() const; 40 | int get_n_bytes_left() const; 41 | 42 | const std::vector peek() const; 43 | }; 44 | 45 | uint64_t get_variable_size_integer(buffer_in & data_source, const int len); 46 | -------------------------------------------------------------------------------- /www/default/.well-known/security.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNED MESSAGE----- 2 | Hash: SHA512 3 | 4 | Contact: mailto:mail@vanheusden.com 5 | Contact: mailto:folkert.mobiel@gmail.com 6 | Contact: mailto:info@hackerspace-gouda.nl 7 | Expires: 2036-12-31T23:00:00.000Z 8 | Encryption: https://hackerspace-gouda.nl/key.txt 9 | Preferred-Languages: en 10 | -----BEGIN PGP SIGNATURE----- 11 | 12 | iQIzBAEBCgAdFiEERCU/j0MkBSbBnbCTa2RV7f7tO9EFAmQPjn8ACgkQa2RV7f7t 13 | O9H1og/8DwXwz3/yK6OgmD8dgH71FUxMfHFO90m0qTaqcb5gqvJvmvJpKBHdbHvb 14 | svXfmID7CbeMM0LtjSbygyrtQozdOjPT6goh6t8E3EnGefzgo9I9hWPl9w2edfat 15 | Cev924r7wl9DW0SiFppLgDp/7dpDBgi8teaYO98lca+i4IMGGQ8534kEk8Eamnpf 16 | uY20NzU82Yv9vHKWS653001Wq52IW15IZeHnNeuV2wuoQdFCcX9L0jUTq57UeZBD 17 | iJ5WrCtSSv9MPYkqYOSp0kqX+j6wY5H4FQz7bY+lh8qoMTFzKj/iIAipf9XQJiO5 18 | f6WtfoAizw7lXHItIOzADpS/Erm8/dpxew1Gj+r/eWaFu8tjtK3TgZeaQl/5mI8M 19 | bTcNgle5g20GBGizZcO7dOx0tXo+qSucIMw6CT+TxovkXoq90gHjT8cuKG2TAvgT 20 | p2ErHK/4QiNjqaij7a/sJrzw/4x9Gw+eXvanUykP0i5QNe1mpCMzvT5fX/pUJGc2 21 | v1/kn2RidDvBVbs3ZpZXGEGa1DUJemDUWKhlsGob9f4wWWyXI431W+1eCFojQx1N 22 | hvpbazrmFFm0PKw8GPwbmErbFovDxT3psg6lKdksL3Kinz3EjuRnuj3Dr3g07FfF 23 | BPMmKLxcwNKdgP3tP8UBNaAm1XJKy7J6fRf8BUHQwspkt/pKSSc= 24 | =pOQ0 25 | -----END PGP SIGNATURE----- 26 | -------------------------------------------------------------------------------- /cert.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDazCCAlOgAwIBAgIUFZ7l3drYJyYdusiJSUfZsF18ho0wDQYJKoZIhvcNAQEL 3 | BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM 4 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjExMjQwODAyNTNaFw0yMzEx 5 | MjQwODAyNTNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw 6 | HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB 7 | AQUAA4IBDwAwggEKAoIBAQC/EtOoOBvqU3eKQbeoJHkxumX3GPKl+OmNDAjzBrKi 8 | qtNqW6+kVgK9Ic6Xwpcto6BsCPqyNF+CqI4yjtPAUdIqh/3/vNz8Bl+6wnVXStBF 9 | 6aMyYaJ+GyLJUX4rv+IVbtZV1HhYpqM+WrQQKhUYJZFnKPzODNqVkLiR9TstuuvK 10 | y74OcriFHZrogf3GltSBNW8D9sHQQSiNCXbi2z1YQYEG6zVKau48RPEDvPjloEX7 11 | ruvzOWHSMWP0x/tG90ZeAXEwIoWHZimyiBy822kn9u0FYcrZCwXUpRO4iK/uA4kT 12 | QZ+UQ0gTZTicL64RMQsJQMVKDbv6bfpf94I0qvvNRilZAgMBAAGjUzBRMB0GA1Ud 13 | DgQWBBT3myCIGAg9qCBFGYzXGjl0d2s8lzAfBgNVHSMEGDAWgBT3myCIGAg9qCBF 14 | GYzXGjl0d2s8lzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBW 15 | uCDSDAWCWyDaV1JI+PofQxC3nNeQ1pbh/bGaK9OPqrnwC+ytyhHKr2yzPMimkrOi 16 | L+0P/aS/fPwlU2G8rn8GT6I0TFto7gSP4T9d/81+t8APlhRn6F8UrexJAiYLaztL 17 | ui06UCELv8/lukL3wbCENI15nFOl5u0+qWDdfWSqtfD2HvmNGnXqD34ORKXfj6LW 18 | GAGTT1EQm7l7JJjijaWR2TORgGPXOEPalo4jxtdng+NW15UL1dUrSdg6BGF1x1es 19 | sdu/ZwWqU5rFEgAQ6tzP9fe9sgsbMf7VQA+fcBVypVLpFzBkZu3e9/qQ3MP6FawJ 20 | bI36V5t8GFryoP1THahj 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /www/www.hackerspace-gouda.nl/favicon.ico: -------------------------------------------------------------------------------- 1 | nu al de meest sympathieke hackerspace van Nederland

hackerspace gouda

wat is een hackerspace?

Bij "hackerspace" denkt men vaak aan inbreken in computers en dan boevenstreken uithalen. Dat is echter niet de betekenis die origineel aan het woord gegeven is. Dat was "creatief omgaan met spullen", dat kan zijn met computers maar is niet per definitie zo.

een hackerspace? in Gouda...?

Hackerspace Gouda is nog in oprichting. Kom in ieder geval alvast chatten op IRC (#hsgouda op FreeNode).

contact?

Mailtjes zijn welkom op het volgende adres: info@hackerspace-gouda.nl

Deze website draait NIET op apache of nginx ofzo, deze draait op een zelf-geschreven IP-stack met daarop een zelf-geschreven web-server en is daarmee de 1e hackerspace (wereldwijd) die dat doet!

NTP (tijd) server

Hackerspace Gouda heeft een publieke tijd-server (NTP server) draaien op: ntp.hackerspace-gouda.nl

-------------------------------------------------------------------------------- /phys_vpn_insertion_point.h: -------------------------------------------------------------------------------- 1 | // (C) 2024 by folkert van heusden , released under Apache License v2.0 2 | 3 | #pragma once 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "any_addr.h" 11 | #include "phys.h" 12 | #include "network_layer.h" 13 | #include "stats.h" 14 | #include "vpn.h" 15 | 16 | class phys_vpn_insertion_point : public phys 17 | { 18 | private: 19 | vpn *v { nullptr }; 20 | 21 | public: 22 | phys_vpn_insertion_point(const size_t dev_index, stats *const s, const std::string & dev_name, router *const r, const any_addr & my_mac); 23 | phys_vpn_insertion_point(const phys_vpn_insertion_point &) = delete; 24 | virtual ~phys_vpn_insertion_point(); 25 | 26 | void start() override; 27 | 28 | // into the vpn 29 | bool transmit_packet(const any_addr & dest_mac, const any_addr & src_mac, const uint16_t ether_type, const uint8_t *payload, const size_t pl_size) override; 30 | 31 | any_addr::addr_family get_phys_type() override { return any_addr::mac; } 32 | 33 | void configure_endpoint(vpn *const v); 34 | // from the vpn 35 | bool insert_packet(const uint16_t ether_type, const uint8_t *const payload, const size_t pl_size); 36 | bool insert_packet(const any_addr & dst_mac, const any_addr & src_mac, const uint16_t ether_type, const uint8_t *const payload, const size_t pl_size); 37 | 38 | void operator()() override; 39 | }; 40 | -------------------------------------------------------------------------------- /lldp.h: -------------------------------------------------------------------------------- 1 | // (C) 2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "network_layer.h" 11 | #include "phys.h" 12 | #include "router.h" 13 | #include "stats.h" 14 | #include "time.h" 15 | 16 | 17 | class lldp : public network_layer 18 | { 19 | private: 20 | std::thread *th { nullptr }; 21 | 22 | interruptable_sleep stop_flag; 23 | 24 | const any_addr my_mac; 25 | const any_addr mgmt_addr; 26 | const int interface_idx; 27 | 28 | void add_tlv(std::vector *const target, const uint8_t type, const std::vector & payload); 29 | std::vector generate_lldp_packet(); 30 | 31 | public: 32 | lldp(stats *const s, const any_addr & my_mac, const any_addr & mgmt_addr, const int interface_idx, router *const r); 33 | virtual ~lldp(); 34 | 35 | any_addr get_addr() const override { return any_addr(); } 36 | 37 | bool transmit_packet(const std::optional & dst_mac, const any_addr & dst_ip, const any_addr & src_ip, const uint8_t protocol, const uint8_t *payload, const size_t pl_size, const uint8_t *const header_template) override; 38 | 39 | virtual int get_max_packet_size() const override { return 1500; } 40 | 41 | void queue_incoming_packet(phys *const interface, packet *p) override; 42 | 43 | void operator()() override; 44 | }; 45 | -------------------------------------------------------------------------------- /network_layer.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #include 3 | #include 4 | 5 | #include "transport_layer.h" 6 | #include "log.h" 7 | #include "network_layer.h" 8 | 9 | 10 | constexpr size_t pkts_max_size { 128 }; 11 | 12 | network_layer::network_layer(stats *const s, const std::string & stats_name, router *const r) : r(r) 13 | { 14 | pkts = new fifo(s, stats_name, pkts_max_size); 15 | } 16 | 17 | network_layer::~network_layer() 18 | { 19 | delete pkts; 20 | } 21 | 22 | void network_layer::register_protocol(const uint8_t protocol, transport_layer *const p) 23 | { 24 | prot_map.insert({ protocol, p }); 25 | 26 | p->register_ip(this); 27 | } 28 | 29 | transport_layer *network_layer::get_transport_layer(const uint8_t protocol) 30 | { 31 | auto it = prot_map.find(protocol); 32 | if (it == prot_map.end()) 33 | return nullptr; 34 | 35 | return it->second; 36 | } 37 | 38 | void network_layer::queue_incoming_packet(phys *const interface, packet *p) 39 | { 40 | if (pkts->try_put({ interface, p }) == false) { 41 | DOLOG(ll_debug, "network_layer: packet dropped\n"); 42 | 43 | delete p; 44 | } 45 | } 46 | 47 | uint16_t ip_checksum(const uint16_t *const p, const size_t n) 48 | { 49 | uint32_t cksum = 0; 50 | 51 | for(size_t i=0; i> 16) + (cksum & 0xffff); 55 | cksum += cksum >> 16; 56 | 57 | return ~cksum; 58 | } 59 | -------------------------------------------------------------------------------- /stats_utils.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #include 3 | #include 4 | 5 | #include "fifo_stats.h" 6 | #include "str.h" 7 | 8 | 9 | std::string stats_to_json(const uint8_t *const p, const std::vector > & fs, const int size) 10 | { 11 | std::string out; 12 | 13 | const uint8_t *const p_end = &p[size]; 14 | const uint8_t *cur_p = p; 15 | 16 | bool first_gen = true; 17 | while(cur_p < p_end && cur_p[16]) { 18 | uint64_t *cnt_p = (uint64_t *)cur_p; 19 | uint64_t *cnt_p2 = (uint64_t *)(cur_p + 8); 20 | 21 | if (first_gen) { 22 | out = "{ "; 23 | first_gen = false; 24 | } 25 | else { 26 | out += ", "; 27 | } 28 | 29 | out += myformat("\"%s\" : ", &cur_p[16]); 30 | 31 | if (*cnt_p2) 32 | out += myformat("%f", *cnt_p / double(*cnt_p2)); 33 | else 34 | out += myformat("%lu", *cnt_p); 35 | 36 | cur_p += 48; 37 | } 38 | 39 | out += ", \"fifo\":["; 40 | bool first_fs = true; 41 | for(auto & pair : fs) { 42 | if (first_fs) 43 | first_fs = false; 44 | else 45 | out += ", "; 46 | 47 | out += myformat("{ \"name\":\"%s\", \"values\":[", pair.first.c_str()); 48 | 49 | int n_counters = pair.second->get_size(); 50 | for(int i=0; iget_counter(i)); 55 | } 56 | 57 | out += "] }"; 58 | } 59 | out += "]"; 60 | 61 | out += " }"; 62 | 63 | return out; 64 | } 65 | -------------------------------------------------------------------------------- /address_cache.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2024 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "phys.h" 9 | #include "network_layer.h" 10 | #include "stats.h" 11 | #include "time.h" 12 | 13 | 14 | class address_cache 15 | { 16 | protected: 17 | typedef struct { 18 | uint64_t ts; 19 | any_addr addr; 20 | phys *interface; 21 | } address_entry_t; 22 | 23 | static std::shared_mutex cache_lock; 24 | static std::map cache; 25 | static std::map mac_cache; 26 | 27 | interruptable_sleep cleaner_stop; 28 | std::thread *cleaner_th { nullptr }; 29 | 30 | uint64_t *address_cache_requests { nullptr }, *address_cache_for_me { nullptr }; 31 | uint64_t *address_cache_req { nullptr }, *address_cache_hit { nullptr }; 32 | uint64_t *address_cache_store { nullptr }, *address_cache_update { nullptr }; 33 | 34 | void cache_cleaner(); 35 | 36 | public: 37 | address_cache(stats *const s); 38 | virtual ~address_cache(); 39 | 40 | void update_cache(const any_addr & mac, const any_addr & ip, phys *const interface, const bool static_entry = false); 41 | 42 | void add_static_entry(phys *const interface, const any_addr & mac, const any_addr & ip); 43 | 44 | virtual std::pair query_cache(const any_addr & ip, const bool static_entry = false); 45 | virtual phys * query_mac_cache(const any_addr & mac); 46 | 47 | static void dump_cache(); 48 | }; 49 | -------------------------------------------------------------------------------- /stats.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "fifo_stats.h" 10 | #include "snmp_data.h" 11 | 12 | 13 | void stats_inc_counter(uint64_t *const p); 14 | void stats_add_counter(uint64_t *const p, const uint64_t value); 15 | void stats_set(uint64_t *const p, const uint64_t value); 16 | void stats_add_average(uint64_t *const p, const int value); 17 | 18 | typedef struct _stats_t_{ 19 | uint64_t *p { nullptr }; 20 | std::string oid; 21 | 22 | _stats_t_() { 23 | } 24 | } stats_t; 25 | 26 | typedef struct _oid_t_ { 27 | stats_t s; 28 | int index; 29 | std::map children; 30 | } oid_t; 31 | 32 | class stats 33 | { 34 | private: 35 | const int size { 0 }; 36 | snmp_data *const sd { nullptr }; 37 | int fd { -1 }; 38 | uint8_t *p { nullptr }; 39 | int len { 0 }; 40 | 41 | std::map fs; 42 | 43 | mutable std::mutex lock; 44 | 45 | public: 46 | stats(const int size, snmp_data *const sd); 47 | virtual ~stats(); 48 | 49 | uint64_t * register_stat(const std::string & name, const std::string & oid = "", const snmp_integer::snmp_integer_type type = snmp_integer::si_integer); 50 | 51 | void register_fifo_stats(const std::string & name, fifo_stats *const fs); 52 | std::vector > get_fifo_stats() const; 53 | 54 | std::string to_json() const; 55 | }; 56 | -------------------------------------------------------------------------------- /packet.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2020 by folkert van heusden , released under Apache License v2.0 2 | 3 | #include "packet.h" 4 | #include "utils.h" 5 | 6 | 7 | packet::packet(const timespec & ts_in, const any_addr & src_mac_addr, const any_addr & src_addr, const any_addr & dst_addr, const uint8_t *const in, const int size, const uint8_t *const header, const int header_size, const std::string & log_prefix, const bool is_forwarded) : 8 | ts(ts_in), 9 | src_mac_addr(src_mac_addr), src_addr(src_addr), dst_addr(dst_addr), 10 | log_prefix(log_prefix), 11 | is_forwarded(is_forwarded) 12 | { 13 | this->size = size; 14 | data = ::duplicate(in, size); 15 | 16 | this->header_size = header_size; 17 | this->header = header_size ? ::duplicate(header, header_size) : nullptr; 18 | } 19 | 20 | packet::packet(const timespec & ts_in, const any_addr & src_addr, const any_addr & dst_addr, const uint8_t *const in, const int size, const uint8_t *const header, const int header_size, const std::string & log_prefix, const bool is_forwarded) : 21 | ts(ts_in), 22 | src_mac_addr(src_addr), src_addr(src_addr), dst_addr(dst_addr), 23 | log_prefix(log_prefix), 24 | is_forwarded(is_forwarded) 25 | { 26 | this->size = size; 27 | data = ::duplicate(in, size); 28 | 29 | this->header_size = header_size; 30 | this->header = header_size ? ::duplicate(header, header_size) : nullptr; 31 | } 32 | 33 | packet::~packet() 34 | { 35 | delete [] header; 36 | delete [] data; 37 | } 38 | 39 | packet *packet::duplicate() const 40 | { 41 | return new packet(ts, src_mac_addr, src_addr, dst_addr, data, size, header, header_size, log_prefix, is_forwarded); 42 | } 43 | -------------------------------------------------------------------------------- /ipv6.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "ndp.h" 10 | #include "network_layer.h" 11 | #include "phys.h" 12 | #include "router.h" 13 | #include "stats.h" 14 | #include "transport_layer.h" 15 | 16 | 17 | class arp; 18 | 19 | class ipv6 : public network_layer 20 | { 21 | private: 22 | std::vector ths; 23 | 24 | ndp *indp { nullptr }; 25 | 26 | const any_addr myip; 27 | 28 | uint64_t *ip_n_pkt { nullptr }; 29 | uint64_t *ip_n_disc { nullptr }; 30 | uint64_t *ip_n_del { nullptr }; 31 | uint64_t *ip_n_out_req { nullptr }; 32 | uint64_t *ip_n_out_disc { nullptr }; 33 | uint64_t *ipv6_n_pkt { nullptr }; 34 | uint64_t *ipv6_not_me { nullptr }; 35 | uint64_t *ipv6_ttl_ex { nullptr }; 36 | uint64_t *ipv6_unk_prot { nullptr }; 37 | uint64_t *ipv6_n_tx { nullptr }; 38 | uint64_t *ipv6_tx_err { nullptr }; 39 | 40 | public: 41 | ipv6(stats *const s, ndp *const indp, const any_addr & myip, router *const r, const int n_threads); 42 | virtual ~ipv6(); 43 | 44 | any_addr get_addr() const override { return myip; } 45 | 46 | bool transmit_packet(const std::optional & dst_mac, const any_addr & dst_ip, const any_addr & src_ip, const uint8_t protocol, const uint8_t *payload, const size_t pl_size, const uint8_t *const header_template) override; 47 | 48 | virtual int get_max_packet_size() const override { return default_pdev->get_max_packet_size() - 40 /* 40 = size of IPv6 header */; } 49 | 50 | void operator()() override; 51 | }; 52 | -------------------------------------------------------------------------------- /dns.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "any_addr.h" 8 | #include "application.h" 9 | #include "udp.h" 10 | 11 | 12 | typedef struct { 13 | any_addr a; 14 | time_t t; 15 | int max_age; 16 | } dns_a_rec_t; 17 | 18 | typedef struct { 19 | std::string name; 20 | time_t t; 21 | int max_age; 22 | } dns_cname_rec_t; 23 | 24 | class dns : public application 25 | { 26 | private: 27 | udp *const u { nullptr }; 28 | 29 | const any_addr my_ip; 30 | const any_addr dns_ip; 31 | 32 | std::thread *th { nullptr }; 33 | 34 | uint64_t *dns_queries { nullptr }; 35 | uint64_t *dns_queries_hit { nullptr }; 36 | uint64_t *dns_queries_miss { nullptr }; 37 | uint64_t *dns_queries_alien_reply { nullptr }; 38 | uint64_t *dns_queries_to { nullptr }; 39 | 40 | std::mutex lock; 41 | std::map a_aaaa_cache; 42 | std::map cname_cache; 43 | std::condition_variable updated; 44 | 45 | public: 46 | dns(stats *const s, udp *const u, const any_addr & my_ip, const any_addr & dns_ip); 47 | virtual ~dns(); 48 | 49 | // verify if packet comes from 'dns_a'! 50 | void input(const any_addr & src_ip, int src_port, const any_addr & dst_ip, int dst_port, packet *p, session_data *const pd); 51 | 52 | // send query to dns, wait for 'updated' and then 53 | // check if set in chache. if not, wait. upto to ms. 54 | std::optional query(const std::string & hostname, const int to); 55 | 56 | // flush cache periodically 57 | void operator()(); 58 | }; 59 | -------------------------------------------------------------------------------- /udp.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2023 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "packet.h" 9 | #include "stats.h" 10 | #include "transport_layer.h" 11 | #include "types.h" 12 | 13 | 14 | class icmp; 15 | class ipv4; 16 | class session_data; 17 | 18 | typedef struct { 19 | std::function cb; 20 | session_data *private_data; 21 | } cb_t; 22 | 23 | class udp : public transport_layer 24 | { 25 | private: 26 | icmp *const icmp_; 27 | 28 | // src ip, src port, dest ip (=local), dest port, payload-packet 29 | std::map callbacks; 30 | std::shared_mutex cb_lock; 31 | 32 | std::map allocated_ports; 33 | std::mutex ports_lock; 34 | 35 | uint64_t *udp_requests { nullptr }; 36 | uint64_t *udp_refused { nullptr }; 37 | 38 | std::thread *th2 { nullptr }; 39 | 40 | public: 41 | udp(stats *const s, icmp *const icmp_, const int n_threads); 42 | virtual ~udp(); 43 | 44 | void add_handler(const int port, std::function h, session_data *const pd); 45 | void remove_handler(const int port); 46 | 47 | bool transmit_packet(const any_addr & dst_ip, const int dst_port, const any_addr & src_ip, const int src_port, const uint8_t *payload, const size_t pl_size); 48 | 49 | int allocate_port(); 50 | void unallocate_port(const int port); 51 | void update_port_ts(const int port); 52 | void port_cleaner(); 53 | 54 | virtual void operator()() override; 55 | }; 56 | -------------------------------------------------------------------------------- /vpn.h: -------------------------------------------------------------------------------- 1 | // (C) 2024 by folkert van heusden , released under Apache License v2.0 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "any_addr.h" 11 | #include "application.h" 12 | #include "stats.h" 13 | 14 | 15 | class packet; 16 | class phys_vpn_insertion_point; 17 | class udp; 18 | 19 | class vpn : public application 20 | { 21 | private: 22 | phys_vpn_insertion_point *const phys; 23 | DES_cblock key; 24 | DES_key_schedule sched_encrypt; 25 | DES_key_schedule sched_decrypt; 26 | udp *const u; 27 | const any_addr my_mac; 28 | const any_addr my_ip; 29 | const int my_port; 30 | const any_addr peer_ip; 31 | const int peer_port; 32 | uint8_t ivec_encrypt[8] { 0 }; 33 | uint8_t ivec_decrypt[8] { 0 }; 34 | 35 | uint64_t *vpn_recv { nullptr }; 36 | uint64_t *vpn_send { nullptr }; 37 | 38 | public: 39 | vpn(phys_vpn_insertion_point *const phys, stats *const s, udp *const u, const any_addr & my_ip, const int my_port, const any_addr & peer_ip, const int peer_port, const std::string & psk); 40 | vpn(const vpn &) = delete; 41 | virtual ~vpn(); 42 | 43 | void input(const any_addr & src_ip, int src_port, const any_addr & dst_ip, int dst_port, packet *p, session_data *const pd); 44 | 45 | bool transmit_packet(const any_addr & dst_mac, const any_addr & src_mac, const uint16_t ether_type, const uint8_t *const payload, const size_t pl_size); 46 | 47 | void operator()(); 48 | }; 49 | -------------------------------------------------------------------------------- /snmprommel.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | import random 4 | import socket 5 | import sys 6 | 7 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 8 | 9 | def get_random_bytes(n): 10 | return bytes([random.getrandbits(8) for _ in range(0, n)]) 11 | 12 | def append(a, b): 13 | for by in b: 14 | a.append(by) 15 | 16 | return a 17 | 18 | def get_msg(max_len): 19 | if max_len < 2: 20 | return bytearray() 21 | 22 | msg = bytearray() 23 | 24 | msg.append(get_random_bytes(1)[0]) # identifier 25 | 26 | len_ = random.randrange(0, max_len) 27 | msg = append(msg, len_.to_bytes(1, 'big')) 28 | 29 | msg = append(msg, get_random_bytes(len_)) 30 | 31 | return msg 32 | 33 | def req_msg(max_len): 34 | if max_len < 2: 35 | return bytearray() 36 | 37 | n = random.randrange(0, 8) 38 | 39 | msg = bytearray() 40 | msg.append(0x30) 41 | msg.append(255) # to be adjusted 42 | 43 | len_ = 0 44 | 45 | for i in range(0, n): 46 | if random.randrange(0, 3) == 0: 47 | curm = req_msg(max_len - len_ - 2) 48 | 49 | len_ += len(curm) 50 | msg = append(msg, curm) 51 | 52 | else: 53 | curm = get_msg(max_len - len_ - 2) 54 | 55 | len_ += len(curm) 56 | msg = append(msg, curm) 57 | 58 | if len_ == max_len - 2: 59 | break 60 | 61 | msg[1] = (len_.to_bytes(1, 'big'))[0] 62 | 63 | return msg 64 | 65 | while True: 66 | sel = random.getrandbits(1) 67 | 68 | if sel == 0: # invalid length 69 | msg = get_random_bytes(random.randrange(1, 1500)) 70 | 71 | elif sel == 1: # sequence 72 | msg = req_msg(255) 73 | 74 | s.sendto(msg, (sys.argv[1], 161)) 75 | -------------------------------------------------------------------------------- /any_addr.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | 8 | #define ANY_ADDR_SIZE 16 9 | 10 | class any_addr { 11 | public: 12 | enum addr_family { ipv4, mac, ax25, ipv6 }; 13 | 14 | private: 15 | addr_family af { mac }; 16 | 17 | uint8_t addr[ANY_ADDR_SIZE] { 0 }; // fits IPv4 & 6 18 | int addr_size { 0 }; 19 | bool set_ { false }; 20 | 21 | uint16_t get_word(const int nr) const; 22 | 23 | public: 24 | any_addr(); 25 | any_addr(const addr_family af, const uint8_t src[]); 26 | any_addr(const any_addr & org); 27 | virtual ~any_addr(); 28 | 29 | bool is_set() const { return set_; } 30 | 31 | any_addr & operator =(const any_addr && other); 32 | any_addr & operator =(const any_addr & other); 33 | bool operator ==(const any_addr & other) const; 34 | bool operator !=(const any_addr & other) const; 35 | bool compare_to(const any_addr & other) const; 36 | bool operator () (const any_addr & lhs, const any_addr & rhs) const; // for std::map::find 37 | bool operator <(const any_addr & rhs) const; // for std::map::find 38 | 39 | void get(uint8_t *const tgt, int *tgt_size) const; 40 | void get(uint8_t *const tgt, int exp_size) const; 41 | const uint8_t & operator[](const int index) const; 42 | 43 | addr_family get_family() const { return af; } 44 | 45 | int get_len() const { return addr_size; } 46 | 47 | uint64_t get_hash() const; 48 | 49 | void set(const addr_family af, const uint8_t src[]); 50 | 51 | std::string to_str() const; 52 | }; 53 | 54 | any_addr parse_address(const std::string & str, const size_t exp_size, const std::string & seperator, const int base); 55 | -------------------------------------------------------------------------------- /phys_kiss.h: -------------------------------------------------------------------------------- 1 | // (C) 2022-2023 by folkert van heusden , released under Apache License v2.0 2 | 3 | #pragma once 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "any_addr.h" 10 | #include "ax25.h" 11 | #include "phys.h" 12 | #include "network_layer.h" 13 | #include "stats.h" 14 | 15 | class phys_kiss : public phys 16 | { 17 | private: 18 | std::mutex send_lock; 19 | 20 | const std::string descriptor; 21 | const any_addr my_callsign; 22 | std::optional > beacon; 23 | const bool add_callsign_repeaters { false }; 24 | 25 | int fd { -1 }; 26 | std::thread *th_beacon { nullptr }; 27 | std::thread *th_kiss_tcp { nullptr }; 28 | 29 | void tcp_kiss_server(); 30 | bool reconnect(); 31 | bool transmit_ax25(const ax25_packet & a); 32 | void send_beacon(); 33 | void handle_kiss(const int fd); 34 | 35 | public: 36 | phys_kiss(const size_t dev_index, stats *const s, const std::string & descr, const any_addr & my_callsign, std::optional > beacon, router *const r, const bool add_callsign_repeaters); 37 | phys_kiss(const phys_kiss &) = delete; 38 | virtual ~phys_kiss(); 39 | 40 | bool transmit_packet(const any_addr & dest_mac, const any_addr & src_mac, const uint16_t ether_type, const uint8_t *payload, const size_t pl_size) override; 41 | 42 | virtual any_addr::addr_family get_phys_type() override { return any_addr::ax25; } 43 | 44 | void operator()() override; 45 | }; 46 | 47 | bool process_kiss_packet(const timespec & ts, const std::vector & in, std::map *const prot_map, router *const r, phys *const source_phys, const std::optional & add_callsign); 48 | -------------------------------------------------------------------------------- /my-key.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/EtOoOBvqU3eK 3 | QbeoJHkxumX3GPKl+OmNDAjzBrKiqtNqW6+kVgK9Ic6Xwpcto6BsCPqyNF+CqI4y 4 | jtPAUdIqh/3/vNz8Bl+6wnVXStBF6aMyYaJ+GyLJUX4rv+IVbtZV1HhYpqM+WrQQ 5 | KhUYJZFnKPzODNqVkLiR9TstuuvKy74OcriFHZrogf3GltSBNW8D9sHQQSiNCXbi 6 | 2z1YQYEG6zVKau48RPEDvPjloEX7ruvzOWHSMWP0x/tG90ZeAXEwIoWHZimyiBy8 7 | 22kn9u0FYcrZCwXUpRO4iK/uA4kTQZ+UQ0gTZTicL64RMQsJQMVKDbv6bfpf94I0 8 | qvvNRilZAgMBAAECggEAGxXl92koxTawHI2vUABc8RMtbscpvSRZUHtobgbriLVI 9 | Leyxq80zgIW2faXXJ2A+wUHOmTdlDfurLfiNhNbfFioGnrDc70RPYAU+fAbTb62s 10 | dYZd8fFnz3ukCTtJ/GQksbBiSkgo85GzsmeSFkUGZRtsJstaAFdZCqZljVh7d1jb 11 | f+7pDKtkEg3/Qi0Yh/Yn4taeSBM07oyDq5GRC5PmKxbHHICLUbqEP2n4cf0SB3jm 12 | xnYs8KHhuS3PwL9AEiQzb6/0tvl0+xy1ykIatOfoR9BoN6alryb58nxn5ejPybil 13 | 9dD4eHXm8ChyrLtG7RPRiCGDIJJoRk+ACGa6d7UGDwKBgQDCEe+vvGz1wCiolGWT 14 | jHZRQiObdCHRAhVOYNi1WhY1Uk1Js4H9Wn2M4WSqlr4ROKBUsgLlCZTH9BeFm0d7 15 | 0qOol/qe4vM8+GZlg36uQ1i/jWoeKtEiKjUrx7AB2POVNb7v6fia3IHy2febp+NI 16 | zJyMGoCeckaXDHZ0F2hEg+vIgwKBgQD8DBjl7+m+aNw+KLeWlIeRSANoBBOhZk9w 17 | 0TCvNdRH46zDSlBNzERI7KxwNALwBIcEgRysvIUC+lUDJW8FbOek6ZK19RiXvOHN 18 | XuyKkZV4KF8QWDDXek5eG0ztotnCHKqCQin8vjNVrzQ0dNneGG5FMT/SownURuKU 19 | h9qXCLPH8wKBgE38pzUXozGeZrhX6fnBGErPKT/vCyfSjn1QrcUyznne+PAFEtec 20 | 5ZcXfDyRFxAUkVl3r3Iax48Sp+Eo5TD9FIdLi4sN6HE34O4qSV398kwHp/03d5Mj 21 | IvrU5AXaCQiM8I24mA6jThUpQjdq4AsBLmeevtDtWzCX8YH1ZhEicj3BAoGBAKij 22 | S3FlYSZ2MI4iXhuRC1eoMCdDOwMtWg+o14MTaBIlgi00JqC3ACUuvX1hP2nqDZB0 23 | 9oOYqwJADetJ+4tMv3x2jyPRdn/n78iiL2/TUoePs3NTHnK9sXuDlqgU4s/esDLx 24 | I/ioJd65mBtU54STIgyHlCVR0rzGJMmuUBHnz6oDAoGAQt/JWC3cVDE2IOju4CJ0 25 | OtpFnpxOvmY5iOvvgPFfk2lr8ptMCAxY8G5ukzEXwxhsX5cWq1VCNBiwPmh+RwWS 26 | fAQ5UQQNm68d/2/gI+hcrLPbcicXsbaTk0akYTx1aD55mcbwNT/hO65tnkZ7gCip 27 | 8f9+/bZD84JPQdORuxNre1U= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /icmp6.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | 6 | #include "any_addr.h" 7 | #include "transport_layer.h" 8 | #include "icmp.h" 9 | #include "mac_resolver.h" 10 | #include "ndp.h" 11 | #include "stats.h" 12 | 13 | 14 | class phys; 15 | class router; 16 | 17 | class icmp6 : public icmp 18 | { 19 | private: 20 | const any_addr my_mac; 21 | const any_addr my_ip; 22 | 23 | router *const r { nullptr }; 24 | phys *const interface{ nullptr }; 25 | 26 | uint64_t *icmp6_requests { nullptr }; 27 | uint64_t *icmp6_transmit { nullptr }; 28 | uint64_t *icmp6_error { nullptr }; 29 | 30 | any_addr all_router_multicast_addr; 31 | 32 | ndp *indp { nullptr }; 33 | 34 | void process_router_advertisement(const packet *const pkt); 35 | 36 | void send_packet(const any_addr *const dst_mac, const any_addr & dst_ip, const any_addr & src_ip, const uint8_t type, const uint8_t code, const uint32_t reserved, const uint8_t *const payload, const int payload_size) const; 37 | 38 | void send_packet_router_soliciation() const; 39 | void send_packet_neighbor_advertisement(const any_addr & peer_mac, const any_addr & peer_ip) const; 40 | void send_ping_reply(const packet *const pkt) const; 41 | 42 | void send_destination_port_unreachable(const any_addr & dst_ip, const any_addr & src_ip, const packet *const p) const override; 43 | 44 | void router_solicitation(); 45 | 46 | public: 47 | icmp6(stats *const s, const any_addr & my_mac, const any_addr & my_ip, router *const r, phys *const interface, const int n_threads); 48 | virtual ~icmp6(); 49 | 50 | void send_ttl_exceeded(const packet *const pkt) const; 51 | void send_packet_neighbor_solicitation(const any_addr & peer_ip) const; 52 | 53 | void operator()() override; 54 | }; 55 | -------------------------------------------------------------------------------- /mac_resolver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "address_cache.h" 8 | #include "any_addr.h" 9 | #include "fifo.h" 10 | #include "network_layer.h" 11 | #include "router.h" 12 | #include "stats.h" 13 | 14 | 15 | class mac_resolver : public address_cache, public network_layer 16 | { 17 | public: 18 | class mac_resolver_result { 19 | public: 20 | std::optional mac; 21 | }; 22 | 23 | protected: 24 | std::map > work; 25 | mutable std::mutex work_lock; 26 | std::condition_variable work_cv; 27 | 28 | bool stop_flag { false }; 29 | 30 | fifo *pkts { nullptr }; 31 | 32 | virtual bool send_request(const any_addr & ip, const any_addr::addr_family af) = 0; 33 | 34 | virtual std::optional check_special_ip_addresses(const any_addr & ip, const any_addr::addr_family family) = 0; 35 | 36 | void dump_work() const; 37 | 38 | public: 39 | mac_resolver(stats *const s, router *const r); 40 | virtual ~mac_resolver(); 41 | 42 | std::optional > get_mac(phys *const interface, const any_addr & ip); 43 | std::optional get_phys_by_mac(const any_addr & mac); 44 | 45 | std::map > dump_state() const; 46 | 47 | any_addr get_addr() const override; 48 | 49 | void queue_incoming_packet(phys *const interface, packet *p) override; 50 | 51 | bool transmit_packet(const std::optional & dst_mac, const any_addr & dst_ip, const any_addr & src_ip, const uint8_t protocol, const uint8_t *payload, const size_t pl_size, const uint8_t *const header_template) override; 52 | 53 | int get_max_packet_size() const override; 54 | 55 | virtual void operator()() override = 0; 56 | }; 57 | -------------------------------------------------------------------------------- /session.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "buffer_out.h" 5 | #include "hash.h" 6 | #include "log.h" 7 | #include "session.h" 8 | 9 | 10 | session::session(pstream *const t, const any_addr & my_addr, const int my_port, const any_addr & their_addr, const int their_port, private_data *const application_private_data) : 11 | t(t), 12 | my_addr(my_addr), 13 | my_port(my_port), 14 | their_addr(their_addr), 15 | their_port(their_port), 16 | application_private_data(application_private_data) 17 | { 18 | if (clock_gettime(CLOCK_REALTIME, &session_created) == -1) 19 | DOLOG(ll_warning, "session: clock_gettime failed\n"); 20 | } 21 | 22 | session::~session() 23 | { 24 | delete callback_private_data; 25 | } 26 | 27 | const any_addr session::get_their_addr() const 28 | { 29 | return their_addr; 30 | } 31 | 32 | const uint16_t session::get_their_port() const 33 | { 34 | return their_port; 35 | } 36 | 37 | const any_addr session::get_my_addr() const 38 | { 39 | return my_addr; 40 | } 41 | 42 | const uint16_t session::get_my_port() const 43 | { 44 | return my_port; 45 | } 46 | 47 | uint64_t session::get_hash() const 48 | { 49 | return get_hash(their_addr, their_port, my_port); 50 | } 51 | 52 | uint64_t session::get_hash(const any_addr & their_addr, const uint16_t their_port, const uint16_t my_port) 53 | { 54 | buffer_out temp; 55 | 56 | temp.add_any_addr(their_addr); 57 | temp.add_net_short(their_port); 58 | temp.add_net_short(my_port); 59 | 60 | // 99194853094755497 is a fibonacci prime (see https://en.wikipedia.org/wiki/List_of_prime_numbers ) 61 | return MurmurHash64A(temp.get_content(), temp.get_size(), 99194853094755497); 62 | } 63 | 64 | void session::set_callback_private_data(session_data *p) 65 | { 66 | callback_private_data = p; 67 | } 68 | 69 | session_data *session::get_callback_private_data() 70 | { 71 | return callback_private_data; 72 | } 73 | -------------------------------------------------------------------------------- /network_layer.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "fifo.h" 13 | #include "packet.h" 14 | #include "router.h" 15 | 16 | 17 | class icmp; 18 | class transport_layer; 19 | class phys; 20 | 21 | typedef struct { 22 | phys *interface; 23 | packet *p; 24 | } fifo_element_t; 25 | 26 | 27 | class network_layer 28 | { 29 | protected: 30 | fifo *pkts { nullptr }; 31 | 32 | phys *default_pdev { nullptr }; 33 | 34 | std::map prot_map; 35 | 36 | icmp *icmp_ { nullptr }; 37 | 38 | router *r { nullptr }; 39 | 40 | public: 41 | network_layer(stats *const s, const std::string & stats_name, router *const r); 42 | virtual ~network_layer(); 43 | 44 | void ask_to_stop() { pkts->interrupt(); } 45 | 46 | virtual any_addr get_addr() const = 0; 47 | 48 | void register_default_phys(phys *const p) { default_pdev = p; } 49 | 50 | void register_protocol(const uint8_t protocol, transport_layer *const p); 51 | 52 | transport_layer *get_transport_layer(const uint8_t protocol); 53 | 54 | void register_icmp(icmp *const icmp_) { this->icmp_ = icmp_; } 55 | 56 | virtual void queue_incoming_packet(phys *const interface, packet *p); 57 | 58 | virtual bool transmit_packet(const std::optional & dst_mac, const any_addr & dst_ip, const any_addr & src_ip, const uint8_t protocol, const uint8_t *payload, const size_t pl_size, const uint8_t *const header_template) = 0; 59 | 60 | virtual int get_max_packet_size() const = 0; 61 | 62 | virtual void operator()() = 0; 63 | }; 64 | 65 | uint16_t ip_checksum(const uint16_t *p, const size_t n); 66 | -------------------------------------------------------------------------------- /tty.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "log.h" 10 | 11 | 12 | int open_tty(const std::string & dev_name, const int bps) 13 | { 14 | int fd = open(dev_name.c_str(), O_RDWR); 15 | 16 | if (fd == -1) { 17 | DOLOG(ll_error, "open %s: %s", dev_name.c_str(), strerror(errno)); 18 | exit(1); 19 | } 20 | 21 | if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { 22 | DOLOG(ll_error, "fcntl(FD_CLOEXEC): %s", strerror(errno)); 23 | exit(1); 24 | } 25 | 26 | struct termios tty; 27 | if (tcgetattr(fd, &tty) != 0) { 28 | DOLOG(ll_error, "tcgetattr on %s: %s\n", dev_name.c_str(), strerror(errno)); 29 | exit(1); 30 | } 31 | 32 | cfsetospeed(&tty, bps); 33 | cfsetispeed(&tty, bps); 34 | 35 | tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars 36 | tty.c_iflag &= ~IGNBRK; // disable break processing 37 | tty.c_lflag = 0; // no signaling chars, no echo, 38 | // no canonical processing 39 | tty.c_oflag = 0; // no remapping, no delays 40 | tty.c_cc[VMIN] = 1; // read blocks 41 | tty.c_cc[VTIME] = 127; // 12.7 seconds read timeout 42 | 43 | tty.c_iflag &= ~(IXON | IXOFF | IXANY); // disable xon/xoff ctrl 44 | 45 | tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls, 46 | // enable reading 47 | tty.c_cflag &= ~(PARENB | PARODD); // shut off parity 48 | tty.c_cflag &= ~CSTOPB; 49 | tty.c_cflag &= ~CRTSCTS; 50 | 51 | if (tcsetattr(fd, TCSANOW, &tty) != 0) { 52 | DOLOG(ll_error, "tcsetattr on %s: %s\n", dev_name.c_str(), strerror(errno)); 53 | exit(1); 54 | } 55 | 56 | return fd; 57 | } 58 | -------------------------------------------------------------------------------- /www/www.hackerspace-gouda.nl/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | nu al de meest sympathieke hackerspace van Nederland 6 | 7 | 8 |
9 |
10 |

hackerspace gouda

11 |

wat is een hackerspace?

12 |

Bij "hackerspace" denkt men vaak aan inbreken in computers en dan boevenstreken uithalen. Dat is echter niet de betekenis die origineel aan het woord gegeven is. Dat was "creatief omgaan met spullen", dat kan zijn met computers maar is niet per definitie zo. Het is bij hackerspaces (i.i.g. die in Nederland) doorgaans niet de bedoeling (niet toegestaan zelfs) dingen te doen die wettelijk gezien niet mogen.

13 | 14 |

een hackerspace? in Gouda...?

15 |

Hackerspace Gouda is nog in oprichting. Kom in ieder geval alvast chatten op IRC (#hsgouda op irc.hackerspace-gouda.nl).

16 | 17 |

contact?

18 |

Mailtjes zijn welkom op het volgende adres: info@hackerspace-gouda.nl

19 |

Bellen kan ook: +31853012914 (of d.m.v. VOIP via sip.hackerspace-gouda.nl)

20 | 21 |

overig

22 |

Deze website draait NIET op apache of nginx ofzo, deze draait op een zelf-geschreven IP-stack met daarop een zelf-geschreven web-server en is (was?) daarmee de 1e hackerspace (wereldwijd) die dat doet!

23 | 24 |

alternatief?

25 |

Ga ook eens kijken bij De Ruimte!

26 | 27 |


28 |

29 |
30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /snmp.h: -------------------------------------------------------------------------------- 1 | // (C) 2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "any_addr.h" 10 | #include "application.h" 11 | #include "snmp_data.h" 12 | #include "stats.h" 13 | 14 | class packet; 15 | class udp; 16 | 17 | typedef struct _oid_req_t_ { 18 | std::vector oids; 19 | uint64_t req_id { 0 }; 20 | int err { 0 }, err_idx { 0 }; 21 | 22 | int version { 0 }; 23 | std::string community; 24 | 25 | _oid_req_t_() { 26 | } 27 | } oid_req_t; 28 | 29 | class snmp : public application 30 | { 31 | private: 32 | snmp_data *const sd; 33 | stats *const s; 34 | udp *const u; 35 | 36 | uint64_t running_since { 0 }; // ms 37 | 38 | uint64_t *snmp_requests { nullptr }, *snmp_invalid { nullptr }; 39 | 40 | bool process_BER(const uint8_t *p, const size_t len, oid_req_t *const oids_req, const bool is_getnext, const int is_top); 41 | uint64_t get_INTEGER(const uint8_t *p, const size_t len); 42 | bool get_OID(const uint8_t *p, const size_t length, std::string *const oid_out); 43 | bool get_type_length(const uint8_t *p, const size_t len, uint8_t *const type, uint8_t *const length); 44 | bool process_PDU(const uint8_t*, const size_t, oid_req_t *const oids_req, const bool is_getnext); 45 | 46 | void add_oid(uint8_t **const packet_out, size_t *const output_size, const std::string & oid); 47 | void add_octet_string(uint8_t **const packet_out, size_t *const output_size, const char *const str); 48 | void gen_reply(oid_req_t & oids_req, uint8_t **const packet_out, size_t *const output_size); 49 | 50 | public: 51 | snmp(snmp_data *const sd, stats *const s, udp *const u); 52 | snmp(const snmp &) = delete; 53 | virtual ~snmp(); 54 | 55 | void input(const any_addr & src_ip, int src_port, const any_addr & dst_ip, int dst_port, packet *p, session_data *const pd); 56 | }; 57 | -------------------------------------------------------------------------------- /hash.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "str.h" 7 | 8 | 9 | std::string md5hex(const std::string & in) 10 | { 11 | unsigned char result[MD5_DIGEST_LENGTH]; 12 | 13 | MD5((unsigned char *)in.c_str(), in.size(), result); 14 | 15 | std::string rc; 16 | for(int i=0; i> 3) + data; 36 | 37 | while(data != end) { 38 | uint64_t k = *data++; 39 | 40 | k *= m; 41 | k ^= k >> r; 42 | k *= m; 43 | 44 | h ^= k; 45 | h *= m; 46 | } 47 | 48 | const uint8_t *data2 = (const uint8_t *)data; 49 | 50 | switch(len & 7) { 51 | case 7: h ^= (uint64_t)(data2[6]) << 48; 52 | case 6: h ^= (uint64_t)(data2[5]) << 40; 53 | case 5: h ^= (uint64_t)(data2[4]) << 32; 54 | case 4: h ^= (uint64_t)(data2[3]) << 24; 55 | case 3: h ^= (uint64_t)(data2[2]) << 16; 56 | case 2: h ^= (uint64_t)(data2[1]) << 8; 57 | case 1: h ^= (uint64_t)(data2[0]); 58 | h *= m; 59 | }; 60 | 61 | h ^= h >> r; 62 | h *= m; 63 | h ^= h >> r; 64 | 65 | return h; 66 | } 67 | 68 | uint32_t crc32(const uint8_t *const data, const size_t n_data, const uint32_t polynomial) 69 | { 70 | const uint32_t p[] = { 0, polynomial }; 71 | 72 | uint32_t crc = 0xFFFFFFFF; 73 | 74 | for(size_t i=0; i>= 1; 81 | 82 | crc ^= p[b]; 83 | 84 | ch >>= 1; 85 | } 86 | } 87 | 88 | return ~crc; 89 | } 90 | -------------------------------------------------------------------------------- /ipv4.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2023 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "duration_events.h" 11 | #include "network_layer.h" 12 | #include "phys.h" 13 | #include "router.h" 14 | #include "stats.h" 15 | #include "transport_layer.h" 16 | 17 | 18 | class arp; 19 | 20 | class ipv4 : public network_layer 21 | { 22 | private: 23 | std::vector ths; 24 | 25 | arp *const iarp { nullptr }; 26 | 27 | const any_addr myip; 28 | 29 | const bool forward { false }; 30 | 31 | uint64_t *ip_n_pkt { nullptr }; 32 | uint64_t *ip_n_disc { nullptr }; 33 | uint64_t *ip_n_del { nullptr }; 34 | uint64_t *ip_n_out_req { nullptr }; 35 | uint64_t *ip_n_out_disc { nullptr }; 36 | uint64_t *ipv4_n_pkt { nullptr }; 37 | uint64_t *ipv4_not_me { nullptr }; 38 | uint64_t *ipv4_ttl_ex { nullptr }; 39 | uint64_t *ipv4_unk_prot { nullptr }; 40 | uint64_t *ipv4_n_tx { nullptr }; 41 | uint64_t *ipv4_tx_err { nullptr }; 42 | 43 | duration_events transmit_packet_de { "ipv4: transmit packet", 8 }; 44 | duration_events receive_packet_de { "ipv4: receive packet", 8 }; 45 | 46 | void send_ttl_exceeded(const packet *const pkt) const; 47 | 48 | public: 49 | ipv4(stats *const s, arp *const iarp, const any_addr & myip, router *const r, const bool forward, const int n_threads); 50 | virtual ~ipv4(); 51 | 52 | any_addr get_addr() const override { return myip; } 53 | 54 | bool transmit_packet(const std::optional & dst_mac, const any_addr & dst_ip, const any_addr & src_ip, const uint8_t protocol, const uint8_t *payload, const size_t pl_size, const uint8_t *const header_template) override; 55 | 56 | virtual int get_max_packet_size() const override { return default_pdev->get_max_packet_size() - 20 /* 20 = size of IPv4 header (without options, as MyIP does) */; } 57 | 58 | void operator()() override; 59 | }; 60 | -------------------------------------------------------------------------------- /myipnetstat.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | import socket 4 | import sys 5 | 6 | class myipud: 7 | def __init__(self, location): 8 | self.buffer = '' 9 | 10 | self.s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 11 | 12 | try: 13 | self.s.connect(location) 14 | 15 | except FileNotFoundError as e: 16 | print(f'Socket cannot be opened ({e}), is MyIP running?') 17 | sys.exit(0) 18 | 19 | def request(self, req): 20 | req_b = (req + '\n').encode('ascii') 21 | 22 | self.s.send(req_b) 23 | 24 | while True: 25 | lf = self.buffer.find('\n') 26 | 27 | if lf != -1: 28 | rc = self.buffer[0:lf] 29 | 30 | self.buffer = self.buffer[lf + 1:] 31 | 32 | return rc 33 | 34 | data = self.s.recv(4096) 35 | 36 | if len(data) == 0: 37 | rc = self.buffer 38 | self.buffer = '' 39 | return rc 40 | 41 | self.buffer += data.decode('ascii') 42 | 43 | def help(): 44 | print(' * sessions') 45 | print(' * list-devices list the physical devices, to be used with start/stop-pcap') 46 | print(' * start-pcap x start pcap recording on device x') 47 | print(' * stop-pcap x stop pcap recording on device x') 48 | print(' * list-arp x list MAC addresses on device x') 49 | 50 | if len(sys.argv) == 1: 51 | help() 52 | sys.exit(1) 53 | 54 | mi = myipud('/tmp/myipstats.sock') 55 | 56 | if sys.argv[1] == 'sessions': 57 | print(mi.request('sessions')) 58 | 59 | elif sys.argv[1] == 'list-devices': 60 | print(mi.request('list-devices')) 61 | 62 | elif sys.argv[1] == 'start-pcap': 63 | print(mi.request('start-pcap|%s' % sys.argv[2])) 64 | 65 | elif sys.argv[1] == 'stop-pcap': 66 | print(mi.request('stop-pcap|%s' % sys.argv[2])) 67 | 68 | elif sys.argv[1] == 'list-arp': 69 | print(mi.request('list-arp|%s' % sys.argv[2])) 70 | 71 | else: 72 | help(); 73 | -------------------------------------------------------------------------------- /vpn.cfg: -------------------------------------------------------------------------------- 1 | logging = { 2 | file="myip.log"; 3 | level_file="debug"; 4 | level_screen="debug"; 5 | } 6 | 7 | environment = { 8 | chdir-path="/tmp" 9 | run-as=0 10 | run-in=0 11 | 12 | ifup="/home/folkert/MyIP/vpn-go.sh" 13 | #ifdown= 14 | 15 | stats-socket="/tmp/myipstats.sock"; 16 | 17 | n-router-threads=4; 18 | } 19 | 20 | interfaces = ( 21 | { 22 | type="tap" 23 | 24 | dev-name="myip" 25 | 26 | n-ipv4-threads=4; 27 | 28 | attach-vpn = true; 29 | 30 | ipv4 = { 31 | my-address="192.168.100.120"; 32 | 33 | forwarder = true; 34 | 35 | use-icmp=true; 36 | use-tcp=true; 37 | use-sctp=true; 38 | use-udp=true; 39 | n-icmp-threads=4; 40 | n-sctp-threads=4; 41 | n-tcp-threads=4; 42 | n-udp-threads=4; 43 | } 44 | 45 | mac-address="52:34:84:16:00:02"; 46 | 47 | upstream-dns = "192.168.100.1"; 48 | 49 | routes = ( { # this interface is the default 50 | ip-family = "ipv4"; 51 | network = "0.0.0.0"; 52 | netmask = "0.0.0.0"; 53 | gateway = "192.168.100.1"; 54 | priority = 1; 55 | }, 56 | { 57 | ip-family = "ipv4"; 58 | network = "192.168.100.0"; 59 | netmask = "255.255.255.0"; 60 | priority = 10; 61 | }) 62 | }, 63 | { 64 | type="vpn" 65 | 66 | dev-name="vpntest" 67 | 68 | n-ipv4-threads=4; 69 | 70 | ipv4 = { 71 | my-address="192.168.9.102"; 72 | 73 | forwarder = true; 74 | 75 | use-icmp=true; 76 | use-tcp=true; 77 | use-sctp=true; 78 | use-udp=true; 79 | n-icmp-threads=4; 80 | n-sctp-threads=4; 81 | n-tcp-threads=4; 82 | n-udp-threads=4; 83 | } 84 | 85 | mac-address="52:34:84:16:44:02"; 86 | 87 | upstream-dns = "192.168.100.1"; 88 | 89 | routes = ({ 90 | ip-family = "ipv4"; 91 | network = "192.168.9.0"; 92 | netmask = "255.255.255.0"; 93 | priority = 10; 94 | }) 95 | } 96 | ) 97 | 98 | vpn = { 99 | my-ip = "192.168.100.102"; 100 | my-port = 4100; 101 | peer-ip = "192.168.100.101"; 102 | peer-port = 4100; 103 | key = "Dit is een test!"; 104 | } 105 | -------------------------------------------------------------------------------- /kiss-tnc-pty-server.cfg: -------------------------------------------------------------------------------- 1 | logging = { 2 | file="myip.log"; 3 | level_file="debug"; 4 | level_screen="debug"; 5 | } 6 | 7 | environment = { 8 | chdir-path="/tmp" 9 | run-as=0 10 | run-in=0 11 | 12 | ifup="/home/folkert/Projects/myip/go.sh" 13 | #ifdown= 14 | 15 | stats-socket="/tmp/myipstats.sock"; 16 | 17 | n-router-threads=4; 18 | } 19 | 20 | interfaces = ( 21 | { 22 | # either slip, ppp, udp, promiscuous (for existing interfaces), kiss (AX.25) 23 | # or tap 24 | type="kiss" 25 | 26 | # device name to connect to 27 | descriptor="pty-master:/tmp/kisstnc.lnk" 28 | 29 | # for kiss: 30 | # pty-master:dev-file create a PTY to which kissattach can connect (TNC mode) 31 | # pty-client:dev-file open an existing PTY (TNC client mode) 32 | # tty:dev-file:baudrate open a serial port on which a TNC listens 33 | # tcp-client:host:port connect to a KISS over TCP server 34 | # tcp-server:listen-addr:port listens for a KISS over TCP client 35 | # 36 | #beacon = "Hello, world!"; 37 | #beacon-interval=0; in seconds 38 | 39 | upstream-dns = "8.8.8.8"; 40 | 41 | ipv4 = { 42 | my-address="192.168.32.19"; 43 | 44 | forwarder = true; 45 | 46 | use-icmp=true; 47 | use-tcp=true; 48 | use-udp=true; 49 | use-sctp=true; 50 | n-icmp-threads=4; 51 | n-sctp-threads=4; 52 | n-tcp-threads=4; 53 | n-udp-threads=4; 54 | } 55 | 56 | mac-address="PD9FVH-5"; 57 | 58 | routes-ax25 = ( { 59 | # callsign to route through this interface 60 | callsign = "PD9FVH-1"; 61 | ## route it via the following repeater (optional) 62 | #via-callsign = "PD9FVH-3"; 63 | } 64 | ) 65 | 66 | routes = ( { # this interface is the default 67 | ip-family = "ipv4"; 68 | network = "0.0.0.0"; 69 | netmask = "0.0.0.0"; 70 | gateway = "192.168.32.19"; 71 | priority = 0; 72 | }, 73 | { 74 | ip-family = "ipv4"; 75 | network = "192.168.32.0"; 76 | netmask = "255.255.255.0"; 77 | priority = 10; 78 | }) 79 | } 80 | ) 81 | -------------------------------------------------------------------------------- /packet.h: -------------------------------------------------------------------------------- 1 | // (C) 2020 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "any_addr.h" 9 | 10 | class packet 11 | { 12 | private: 13 | const struct timespec ts { 0, 0 }; 14 | 15 | const any_addr src_mac_addr; 16 | 17 | const any_addr src_addr; 18 | const any_addr dst_addr; 19 | 20 | uint8_t *data; 21 | int size; 22 | 23 | std::string log_prefix; 24 | 25 | // this is required for ICMP: it needs certain fields from the source (IP-)header 26 | uint8_t *header; 27 | int header_size; 28 | 29 | const bool is_forwarded; 30 | 31 | public: 32 | packet(const timespec & ts, const any_addr & src_addr, const any_addr & dst_addr, const uint8_t *const in, const int size, const uint8_t *const header, const int header_size, const std::string & log_prefix, const bool is_forwarded = false); 33 | packet(const timespec & ts, const any_addr & src_mac_addr, const any_addr & src_addr, const any_addr & dst_addr, const uint8_t *const in, const int size, const uint8_t *const header, const int header_size, const std::string & log_prefix, const bool is_forwarded = false); 34 | virtual ~packet(); 35 | 36 | uint8_t *get_data() const { return data; } 37 | std::pair get_payload() const { return { data, size }; } 38 | 39 | bool get_is_forwarded() const { return is_forwarded; } 40 | 41 | int get_size() const { return size; } 42 | 43 | void add_to_log_prefix(const std::string & what) { log_prefix += what; } 44 | 45 | std::string get_log_prefix() const { return log_prefix; } 46 | 47 | const any_addr & get_src_mac_addr() const { return src_mac_addr; } 48 | 49 | const any_addr & get_src_addr() const { return src_addr; } 50 | 51 | const any_addr & get_dst_addr() const { return dst_addr; } 52 | 53 | std::pair get_header() const { return { header, header_size }; } 54 | 55 | struct timespec get_recv_ts() const { return ts; } 56 | 57 | packet *duplicate() const; 58 | }; 59 | -------------------------------------------------------------------------------- /transport_layer.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2020-2023 by folkert van heusden , released under Apache License v2.0 2 | #include 3 | 4 | #include "transport_layer.h" 5 | #include "log.h" 6 | 7 | 8 | constexpr size_t pkts_max_size { 128 }; 9 | 10 | transport_layer::transport_layer(stats *const s, const std::string & stats_name) 11 | { 12 | pkts = new fifo(s, stats_name, pkts_max_size); 13 | } 14 | 15 | transport_layer::~transport_layer() 16 | { 17 | delete pkts; 18 | } 19 | 20 | void transport_layer::queue_packet(packet *p) 21 | { 22 | if (pkts->try_put(p) == false) { 23 | DOLOG(ll_debug, "IP-Protocol: queue full, packet dropped\n"); 24 | 25 | delete p; 26 | } 27 | } 28 | 29 | uint16_t tcp_udp_checksum(const any_addr & src_addr, const any_addr & dst_addr, const bool tcp, const uint8_t *const tcp_payload, const int len) 30 | { 31 | uint16_t checksum { 0 }; 32 | 33 | if (dst_addr.get_family() == any_addr::ipv6) { // IPv6 34 | size_t temp_len = 40 + len + (len & 1); 35 | uint8_t *temp = new uint8_t[temp_len](); 36 | 37 | src_addr.get(&temp[0], 16); 38 | 39 | dst_addr.get(&temp[16], 16); 40 | 41 | temp[32] = len >> 24; 42 | temp[33] = len >> 16; 43 | temp[34] = len >> 8; 44 | temp[35] = len; 45 | 46 | temp[39] = tcp ? 0x06 : 0x11; 47 | 48 | memcpy(&temp[40], tcp_payload, len); 49 | 50 | checksum = ip_checksum((const uint16_t *)temp, temp_len / 2); 51 | 52 | delete [] temp; 53 | } 54 | else if (dst_addr.get_family() == any_addr::ipv4) { // IPv4 55 | size_t temp_len = 12 + len + (len & 1); 56 | uint8_t *temp = new uint8_t[temp_len](); 57 | 58 | src_addr.get(&temp[0], 4); 59 | 60 | dst_addr.get(&temp[4], 4); 61 | 62 | temp[9] = tcp ? 0x06 : 0x11; 63 | 64 | temp[10] = len >> 8; // TCP len 65 | temp[11] = len; 66 | 67 | memcpy(&temp[12], tcp_payload, len); 68 | 69 | checksum = ip_checksum((const uint16_t *)temp, temp_len / 2); 70 | 71 | delete [] temp; 72 | } 73 | else { 74 | DOLOG(ll_debug, "tcp_udp_checksum: cannot handle \"%s\" to \"%s\"\n", src_addr.to_str().c_str(), dst_addr.to_str().c_str()); 75 | } 76 | 77 | return checksum; 78 | } 79 | -------------------------------------------------------------------------------- /kiss-tnc-tcp-client.cfg: -------------------------------------------------------------------------------- 1 | logging = { 2 | file="myip.log"; 3 | level_file="debug"; 4 | level_screen="debug"; 5 | } 6 | 7 | environment = { 8 | chdir-path="/tmp" 9 | run-as=0 10 | run-in=0 11 | 12 | ifup="/home/folkert/Projects/MyIP/go-tnc.sh" 13 | #ifdown= 14 | 15 | stats-socket="/tmp/myipstats.sock"; 16 | 17 | n-router-threads=4; 18 | } 19 | 20 | interfaces = ( 21 | { 22 | # either slip, ppp, udp, promiscuous (for existing interfaces), kiss (IP(v4) 23 | # over AX.25) or tap 24 | type="kiss"; 25 | 26 | descriptor="tcp-client:192.168.64.206:8105"; 27 | 28 | # for kiss: 29 | # descriptor="..."; 30 | # pty-master:dev-file create a PTY to which kissattach can connect (TNC mode) 31 | # pty-client:dev-file open an existing PTY (TNC client mode) 32 | # tty:dev-file:baudrate open a serial port on which a TNC listens 33 | # tcp-client:host:port connect to a KISS over TCP server 34 | # tcp-server:listen-addr:port listens for a KISS over TCP client 35 | # 36 | #beacon = "Hello, world!"; 37 | #beacon-interval=0; in seconds 38 | 39 | # only one kiss interface should have this set to true 40 | # it is the default-gateway equivalent of ipv4 41 | default-interface = true; 42 | 43 | #beacon="Hello, this is KISS over TCP server!"; 44 | #beacon-interval=10; 45 | 46 | upstream-dns = "8.8.8.8"; 47 | 48 | ipv4 = { 49 | my-address="192.168.4.1"; 50 | 51 | use-icmp=true; 52 | use-tcp=true; 53 | use-udp=true; 54 | use-sctp=true; 55 | n-icmp-threads=4; 56 | n-sctp-threads=4; 57 | n-tcp-threads=4; 58 | n-udp-threads=4; 59 | } 60 | 61 | mac-address="PD9FVH-4"; 62 | 63 | routes = ( { # this interface is the default 64 | ip-family = "ipv4"; 65 | network = "0.0.0.0"; 66 | netmask = "0.0.0.0"; 67 | gateway = "192.168.4.1"; 68 | }, 69 | { 70 | ip-family = "ipv4"; 71 | network = "192.168.4.0"; 72 | netmask = "255.255.255.0"; 73 | }) 74 | } 75 | ) 76 | 77 | ntp = { 78 | upstream-ip-address="192.168.64.1"; 79 | port=123; 80 | broadcast=true; 81 | } 82 | -------------------------------------------------------------------------------- /mqtt_client.h: -------------------------------------------------------------------------------- 1 | // (C) 2023 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "buffer_out.h" 10 | #include "fifo.h" 11 | #include "stats.h" 12 | 13 | 14 | class dns; 15 | class tcp; 16 | 17 | typedef enum { mc_resolve, mc_setup, mc_connect, mc_setup_mqtt_session_connect_req, mc_setup_mqtt_session_connect_ackwait, mc_setup_mqtt_subscribe, mc_running, mc_disconnect } mc_state_t; 18 | 19 | class mqtt_client 20 | { 21 | private: 22 | tcp *const t { nullptr }; 23 | dns *const dns_ { nullptr }; 24 | 25 | const std::string mqtt_host; 26 | const int mqtt_port; 27 | 28 | stats *const s { nullptr }; 29 | 30 | std::thread *th { nullptr }; 31 | std::atomic_bool stop_flag { false }; 32 | 33 | std::atomic state { mc_resolve }; 34 | 35 | std::mutex lock; 36 | std::condition_variable cv; 37 | uint8_t *data_in { nullptr }; 38 | size_t n_data_in { 0 }; 39 | 40 | uint16_t msg_id { 0 }; 41 | std::map *> topics; 42 | int src_port { 0 }; 43 | 44 | bool read(uint8_t *target, size_t n); 45 | 46 | std::optional get_variable_length(); 47 | void put_variable_length(uint32_t v, buffer_out *const p); 48 | 49 | buffer_out create_subscribe_message(const std::optional & topic); 50 | buffer_out create_unsubscribe_message(const std::string & topic); 51 | 52 | bool process_command(const uint8_t cmd, const uint8_t *const payload, const size_t pl_len); 53 | 54 | public: 55 | mqtt_client(tcp *const t, dns *const dns_, const std::string & mqtt_host, const int mqtt_port, stats *const s); 56 | virtual ~mqtt_client(); 57 | 58 | void new_data(const buffer_in & data); 59 | void close_session(); 60 | 61 | fifo * subscribe(const std::string & topic); 62 | 63 | void unsubscribe(const std::string & topic, fifo *const msgs); 64 | 65 | void operator()(); 66 | }; 67 | -------------------------------------------------------------------------------- /kiss-tnc-tcp-server.cfg: -------------------------------------------------------------------------------- 1 | logging = { 2 | file="myip.log"; 3 | level_file="debug"; 4 | level_screen="debug"; 5 | } 6 | 7 | environment = { 8 | chdir-path="/tmp" 9 | run-as=0 10 | run-in=0 11 | 12 | ifup="/home/folkert/Projects/MyIP/go-tnc.sh" 13 | #ifdown= 14 | 15 | stats-socket="/tmp/myipstats.sock"; 16 | 17 | n-router-threads=4; 18 | } 19 | 20 | interfaces = ( 21 | { 22 | # either slip, ppp, udp, promiscuous (for existing interfaces), kiss (IP(v4) 23 | # over AX.25) or tap 24 | type="kiss"; 25 | 26 | # serial port device name (can also be a direwolf pts (give -p to direwolf)) 27 | descriptor="tcp-server:0.0.0.0:8105"; 28 | 29 | # for kiss: 30 | # descriptor="..."; 31 | # pty-master:dev-file create a PTY to which kissattach can connect (TNC mode) 32 | # pty-client:dev-file open an existing PTY (TNC client mode) 33 | # tty:dev-file:baudrate open a serial port on which a TNC listens 34 | # tcp-client:host:port connect to a KISS over TCP server 35 | # tcp-server:listen-addr:port listens for a KISS over TCP client 36 | # 37 | #beacon = "Hello, world!"; 38 | #beacon-interval=0; in seconds 39 | 40 | # only one kiss interface should have this set to true 41 | # it is the default-gateway equivalent of ipv4 42 | default-interface = true; 43 | 44 | #beacon="Hello, this is KISS over TCP server!"; 45 | #beacon-interval=10; 46 | 47 | upstream-dns = "8.8.8.8"; 48 | 49 | ipv4 = { 50 | my-address="192.168.32.19"; 51 | 52 | use-icmp=true; 53 | use-tcp=true; 54 | use-udp=true; 55 | use-sctp=true; 56 | n-icmp-threads=4; 57 | n-sctp-threads=4; 58 | n-tcp-threads=4; 59 | n-udp-threads=4; 60 | } 61 | 62 | mac-address="PD9FVH-1"; 63 | 64 | routes = ( { # this interface is the default 65 | ip-family = "ipv4"; 66 | network = "0.0.0.0"; 67 | netmask = "0.0.0.0"; 68 | gateway = "192.168.32.19"; 69 | }, 70 | { 71 | ip-family = "ipv4"; 72 | network = "192.168.32.0"; 73 | netmask = "255.255.255.0"; 74 | }) 75 | } 76 | ) 77 | 78 | ntp = { 79 | upstream-ip-address="192.168.64.1"; 80 | port=123; 81 | broadcast=true; 82 | } 83 | -------------------------------------------------------------------------------- /session.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "any_addr.h" 9 | #include "str.h" 10 | #include "types.h" 11 | 12 | 13 | class pstream; 14 | 15 | class session { 16 | protected: 17 | pstream *const t { nullptr }; 18 | const any_addr my_addr; 19 | const uint16_t my_port { 0 }; 20 | 21 | const any_addr their_addr; 22 | const uint16_t their_port { 0 }; 23 | 24 | session_data *callback_private_data { nullptr }; 25 | 26 | private_data *application_private_data { nullptr }; 27 | 28 | timespec session_created { 0 }; 29 | 30 | std::atomic_bool is_terminating { false }; 31 | 32 | int session_timeout { 300 }; 33 | 34 | session(pstream *const t, const any_addr & my_addr, const int my_port, const any_addr & their_addr, const int their_port, private_data *const application_private_data); 35 | 36 | public: 37 | virtual ~session(); 38 | 39 | std::mutex session_lock; 40 | 41 | // the names of the following 4 methods assume a server situation 42 | const any_addr get_their_addr() const; 43 | 44 | const uint16_t get_their_port() const; 45 | 46 | const any_addr get_my_addr() const; 47 | 48 | const uint16_t get_my_port() const; 49 | 50 | uint64_t get_hash() const; 51 | 52 | std::string to_str() { return myformat("%s:%d <- [%lu] -> %s:%d", get_my_addr().to_str().c_str(), get_my_port(), get_hash(), get_their_addr().to_str().c_str(), get_their_port()); } 53 | 54 | static uint64_t get_hash(const any_addr & their_addr, const uint16_t their_port, const uint16_t my_port); 55 | 56 | void set_is_terminating() { is_terminating = true; } 57 | 58 | bool get_is_terminating() { return is_terminating; } 59 | 60 | void set_callback_private_data(session_data *p); 61 | 62 | session_data *get_callback_private_data(); 63 | 64 | pstream *get_stream_target() { return t; } 65 | 66 | timespec get_session_creation_time() { return session_created; } 67 | 68 | private_data *get_application_private_data() { return application_private_data; } 69 | 70 | virtual std::string get_state_name() const = 0; 71 | 72 | void set_session_timeout(const int duration) { session_timeout = duration; } 73 | 74 | int get_session_timeout() const { return session_timeout; } 75 | }; 76 | -------------------------------------------------------------------------------- /router.cfg: -------------------------------------------------------------------------------- 1 | logging = { 2 | file="myip.log"; 3 | level_file="debug"; 4 | level_screen="debug"; 5 | } 6 | 7 | environment = { 8 | chdir-path="/tmp" 9 | run-as=0 10 | run-in=0 11 | 12 | ifup="/home/folkert/Projects/myip/go.sh" 13 | #ifdown= 14 | 15 | stats-socket="/tmp/myipstats.sock"; 16 | 17 | n-router-threads=4; 18 | } 19 | 20 | interfaces = ( 21 | { 22 | type="tap" 23 | 24 | dev-name="myip" 25 | 26 | n-ipv4-threads=4; 27 | 28 | ipv4 = { 29 | my-address="192.168.3.2"; 30 | 31 | forwarder = true; 32 | 33 | use-icmp=true; 34 | use-tcp=true; 35 | use-sctp=true; 36 | use-udp=true; 37 | n-icmp-threads=4; 38 | n-sctp-threads=4; 39 | n-tcp-threads=4; 40 | n-udp-threads=4; 41 | } 42 | 43 | mac-address="52:34:84:16:44:22"; 44 | 45 | routes = ({ 46 | ip-family = "ipv4"; 47 | network = "192.168.3.0"; 48 | netmask = "255.255.255.0"; 49 | # gateway = "192.168.3.1"; 50 | }) 51 | }, 52 | { 53 | type="tap" 54 | 55 | dev-name="bla" 56 | 57 | n-ipv4-threads=4; 58 | 59 | ipv4 = { 60 | my-address="192.168.122.9"; 61 | 62 | forwarder = true; 63 | 64 | use-icmp=true; 65 | use-tcp=true; 66 | use-sctp=true; 67 | use-udp=true; 68 | n-icmp-threads=4; 69 | n-sctp-threads=4; 70 | n-tcp-threads=4; 71 | n-udp-threads=4; 72 | } 73 | 74 | mac-address="52:34:84:16:44:29"; 75 | 76 | routes = ({ 77 | ip-family = "ipv4"; 78 | network = "192.168.122.0"; 79 | netmask = "255.255.255.0"; 80 | gateway = "192.168.122.1"; 81 | }) 82 | }) 83 | 84 | http = { 85 | web-root="/home/folkert/Projects/myip/www"; 86 | web-logfile="/home/folkert/temp/http_access.log"; 87 | port=80; 88 | mdns="snsv._http._tcp.local."; 89 | } 90 | 91 | https = { 92 | web-root="/home/folkert/Projects/myip/www"; 93 | web-logfile="/home/folkert/temp/http_access.log"; 94 | port=443; 95 | is-https=true; 96 | private-key="/home/folkert/Projects/myip/my-key.key"; 97 | certificate="/home/folkert/Projects/myip/cert.crt"; 98 | } 99 | 100 | vnc = { 101 | ort=5900; 102 | } 103 | 104 | nrpe = { 105 | port=5666; 106 | } 107 | 108 | mqtt = { 109 | port=1883; 110 | } 111 | 112 | snmp = { 113 | port=161; 114 | } 115 | 116 | syslog = { 117 | port=514; 118 | } 119 | -------------------------------------------------------------------------------- /time.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "time.h" 9 | 10 | 11 | uint64_t get_us() 12 | { 13 | struct timespec ts { 0, 0 }; 14 | 15 | if (clock_gettime(CLOCK_REALTIME, &ts) == -1) 16 | fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno)); 17 | 18 | return uint64_t(ts.tv_sec) * uint64_t(1000000l) + uint64_t(ts.tv_nsec / 1000); 19 | } 20 | 21 | uint64_t get_ms() 22 | { 23 | struct timespec ts { 0, 0 }; 24 | 25 | if (clock_gettime(CLOCK_REALTIME, &ts) == -1) 26 | fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno)); 27 | 28 | return uint64_t(ts.tv_sec) * uint64_t(1000) + uint64_t(ts.tv_nsec / 1000000); 29 | } 30 | 31 | uint32_t ms_since_midnight() 32 | { 33 | auto now = std::chrono::system_clock::now(); 34 | 35 | time_t tnow = std::chrono::system_clock::to_time_t(now); 36 | 37 | tm *date = std::localtime(&tnow); 38 | date->tm_hour = 0; 39 | date->tm_min = 0; 40 | date->tm_sec = 0; 41 | 42 | auto midnight = std::chrono::system_clock::from_time_t(std::mktime(date)); 43 | 44 | auto difference = now - midnight; 45 | 46 | return std::chrono::duration_cast(difference).count(); 47 | } 48 | 49 | void myusleep(uint64_t us) 50 | { 51 | struct timespec req; 52 | 53 | req.tv_sec = us / 1000000l; 54 | req.tv_nsec = (us % 1000000l) * 1000l; 55 | 56 | for(;;) { 57 | struct timespec rem { 0, 0 }; 58 | 59 | int rc = nanosleep(&req, &rem); 60 | if (rc == 0 || (rc == -1 && errno != EINTR)) 61 | break; 62 | 63 | memcpy(&req, &rem, sizeof(struct timespec)); 64 | } 65 | } 66 | 67 | interruptable_sleep::interruptable_sleep() 68 | { 69 | } 70 | 71 | void interruptable_sleep::signal_stop() 72 | { 73 | std::unique_lock lck(lock); 74 | 75 | stop = true; 76 | 77 | cv.notify_all(); 78 | } 79 | 80 | // returns true when stop is set 81 | bool interruptable_sleep::sleep(const uint32_t ms) 82 | { 83 | using namespace std::chrono_literals; 84 | 85 | auto wait_until = std::chrono::system_clock::now() + 1ms * ms; 86 | 87 | std::unique_lock lck(lock); 88 | 89 | for(;;) { 90 | if (stop) 91 | return true; 92 | 93 | if (cv.wait_until(lck, wait_until) == std::cv_status::timeout) 94 | return stop; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | what this is 2 | ------------ 3 | This is an implementation of an IP-stack (IPv4/IPv6). 4 | It will listen on a tap-, promiscuous, slip or ppp device for network 5 | frames containg e.g. ARP-requests, IP packets, ICMP(6), UDP and even 6 | NTP, VNC, SIP, MQTT and HTTP requests. Also LLDP, NDP, Socks, syslog, 7 | PPP, SLIP, NRPE, DNS (client), SCTP, MDNS, IRC (server), SNMP and 8 | AX.25. 9 | When multiple interfaces are configured, it can also route between 10 | them. 11 | 12 | Note that this is an experimentation vehicle. 13 | 14 | required 15 | -------- 16 | * C++ compiler 17 | * POSIX system 18 | 19 | how to build 20 | ------------ 21 | Make sure you have the following packages installed: 22 | 23 | * libbsd-dev 24 | * libbearssl-dev 25 | * libssl-dev 26 | * libncurses-dev 27 | * libconfig++-dev 28 | * libspeex-dev 29 | * libsamplerate0-dev 30 | * libturbojpeg0-dev 31 | * zlib1g-dev 32 | * libjansson-dev 33 | * libsndfile1-dev 34 | * libpcap-dev 35 | 36 | then invoke: 37 | 38 | * mkdir build 39 | * cd build 40 | * cmake .. 41 | * make 42 | 43 | how to run 44 | ---------- 45 | As root: 46 | 47 | ./myip configuration-file.cfg 48 | 49 | Look at 'example.cfg' to see what is possible. 50 | 51 | Ideally you have a computer/virtual machine with 2 network-interfaces (or a serial port for PPP/SLIP). Then one port would be the usual LAN port, the other can be assigned to MyIP. The MyIP port can be used as a TAP-device or via "promiscuous-mode". 52 | 53 | 54 | After you have started `myip', a 'myip' network device has appeared. 55 | Of course, your "local IP address" must be configured (remote is the MyIP instance, local is the Linux system; so for the example.ini: 192.168.3.2 is the MyIP address and you could e.g. add 192.168.3.1 to the 'myip' network interface). 56 | 57 | Run: 58 | 59 | ./myiptop 60 | 61 | ...to see network statistics. 62 | 63 | Run ./myiptop -j to see them as JSON. 64 | 65 | notes 66 | ----- 67 | The TCP functionality has some issues. 68 | 69 | demo 70 | ---- 71 | See http://myip.vanheusden.com/ 72 | 73 | It listens to both IPv4 as well as IPv6. It performs HTTP over TCP but also over SCTP. 74 | 75 | It also runs all other protocols supported by MyIP. 76 | 77 | copyright 78 | --------- 79 | (C) 2020-2023 by Folkert van Heusden 80 | 81 | Released under Apache License v2.0 82 | 83 | 84 | my_ip.wav is spoken by https://www.fiverr.com/stephbritishvo 85 | -------------------------------------------------------------------------------- /stats_tracker.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2017-2022 by folkert van heusden, released under Apache License v2.0 2 | 3 | #include 4 | #include 5 | 6 | #include "error.h" 7 | #include "log.h" 8 | #include "stats_tracker.h" 9 | #include "time.h" 10 | #include "utils.h" 11 | 12 | 13 | stats_tracker *st = new stats_tracker(); 14 | 15 | stats_tracker::stats_tracker() 16 | { 17 | th = new std::thread(std::ref(*this)); 18 | } 19 | 20 | stats_tracker::~stats_tracker() 21 | { 22 | if (th) { 23 | m.lock(); 24 | 25 | cv_stop_notify = true; 26 | 27 | cv_stop.notify_one(); 28 | 29 | m.unlock(); 30 | 31 | th->join(); 32 | 33 | delete th; 34 | } 35 | } 36 | 37 | void stats_tracker::operator()() 38 | { 39 | set_thread_name("stats-tracker"); 40 | 41 | for(;;) { 42 | std::unique_lock lock(m); 43 | 44 | cv_stop.wait_for(lock, std::chrono::milliseconds(999)); 45 | 46 | if (cv_stop_notify) 47 | break; 48 | 49 | uint64_t now = get_us(); 50 | int slot_base = now / 1000000; 51 | int slot = slot_base % 5; 52 | 53 | uint64_t latest_ru_ts = get_us(); 54 | 55 | if (getrusage(RUSAGE_SELF, &latest_ru) == -1) { 56 | DOLOG(ll_warning, "getrusage failed: %s\n", strerror(errno)); 57 | 58 | continue; 59 | } 60 | 61 | if (prev_ru_ts) { 62 | if (prev_slot_ru != slot) { 63 | cpu_stats[slot] = 0; 64 | 65 | prev_slot_ru = slot; 66 | } 67 | 68 | struct timeval total_time_used { 0, 0 }; 69 | timeradd(&latest_ru.ru_utime, &latest_ru.ru_stime, &total_time_used); 70 | 71 | struct timeval prev_time_used { 0, 0 }; 72 | timeradd(&prev_ru.ru_utime, &prev_ru.ru_stime, &prev_time_used); 73 | 74 | struct timeval diff_time_used { 0, 0 }; 75 | timersub(&total_time_used, &prev_time_used, &diff_time_used); 76 | 77 | double period = (latest_ru_ts - prev_ru_ts) / 1000000.0; 78 | 79 | cpu_stats[slot] += diff_time_used.tv_sec + diff_time_used.tv_usec / 1000000.0 * period; 80 | } 81 | 82 | prev_ru_ts = latest_ru_ts; 83 | prev_ru = latest_ru; 84 | } 85 | } 86 | 87 | double stats_tracker::get_cpu_usage() const 88 | { 89 | std::unique_lock lock(m); 90 | 91 | uint64_t now = get_us(); 92 | int slot = (now / 1000000) % 5; 93 | 94 | double total = 0.; 95 | 96 | for(int i=0; i<5; i++) { 97 | if (i == slot) 98 | continue; 99 | 100 | total += cpu_stats[i]; 101 | } 102 | 103 | double avg = total / 4; 104 | 105 | return avg; 106 | } 107 | -------------------------------------------------------------------------------- /snmp_elem.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class snmp_elem 9 | { 10 | protected: 11 | uint8_t len { 255 }; 12 | 13 | public: 14 | snmp_elem(); 15 | virtual ~snmp_elem(); 16 | 17 | virtual uint8_t get_size() const { return len; } 18 | 19 | virtual std::pair get_payload() const; 20 | }; 21 | 22 | //--- 23 | 24 | class snmp_integer : public snmp_elem 25 | { 26 | public: 27 | enum snmp_integer_type { si_counter32, si_integer, si_counter64, si_ticks }; 28 | 29 | private: 30 | snmp_integer_type type { si_integer }; 31 | uint64_t v { 0 }; 32 | 33 | public: 34 | explicit snmp_integer(const snmp_integer_type type, const uint64_t v, const int len); 35 | explicit snmp_integer(const snmp_integer_type type, const uint64_t v); 36 | virtual ~snmp_integer(); 37 | 38 | std::pair get_payload() const override; 39 | }; 40 | 41 | //--- 42 | 43 | class snmp_sequence : public snmp_elem 44 | { 45 | protected: 46 | std::vector sequence; 47 | 48 | public: 49 | snmp_sequence(); 50 | virtual ~snmp_sequence(); 51 | 52 | void add(const snmp_elem * const e); 53 | 54 | uint8_t get_size() const override; 55 | 56 | std::pair get_payload() const override; 57 | }; 58 | 59 | //--- 60 | 61 | class snmp_null : public snmp_elem 62 | { 63 | public: 64 | snmp_null(); 65 | virtual ~snmp_null(); 66 | 67 | std::pair get_payload() const override; 68 | }; 69 | 70 | //--- 71 | 72 | class snmp_octet_string : public snmp_elem 73 | { 74 | private: 75 | uint8_t *v { nullptr }; 76 | 77 | public: 78 | explicit snmp_octet_string(const uint8_t *const v, const int len); 79 | virtual ~snmp_octet_string(); 80 | 81 | std::pair get_payload() const override; 82 | }; 83 | 84 | //--- 85 | 86 | class snmp_oid : public snmp_elem 87 | { 88 | private: 89 | uint8_t *v { nullptr }; 90 | 91 | public: 92 | explicit snmp_oid(const std::string & oid); 93 | virtual ~snmp_oid(); 94 | 95 | std::pair get_payload() const override; 96 | }; 97 | 98 | //--- 99 | 100 | class snmp_pdu : public snmp_sequence 101 | { 102 | private: 103 | uint8_t type { 0x00 }; 104 | 105 | public: 106 | explicit snmp_pdu(const uint8_t type); 107 | virtual ~snmp_pdu(); 108 | 109 | std::pair get_payload() const override; 110 | }; 111 | -------------------------------------------------------------------------------- /proc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "str.h" 13 | #include "utils.h" 14 | 15 | 16 | // this code needs more error checking TODO 17 | std::tuple exec_with_pipe(const std::string & command, const std::string & dir, const std::vector & envs) 18 | { 19 | int fd_master { -1 }; 20 | 21 | pid_t pid = forkpty(&fd_master, nullptr, nullptr, nullptr); 22 | if (pid == -1) 23 | error_exit(true, "exec_with_pipe: forkpty failed"); 24 | 25 | if (pid == 0) { 26 | setsid(); 27 | 28 | if (dir.empty() == false && chdir(dir.c_str()) == -1) 29 | error_exit(true, "exec_with_pipe: chdir to %s for %s failed", dir.c_str(), command.c_str()); 30 | 31 | close(2); 32 | (void)open("/dev/null", O_WRONLY); 33 | 34 | // TODO: a smarter way? 35 | int fd_max = sysconf(_SC_OPEN_MAX); 36 | for(int fd=3; fd parts = split(command, " "); 40 | 41 | size_t n_args = parts.size(); 42 | char **pars = new char *[n_args + 1]; 43 | for(size_t i=0; i(parts.at(i).c_str()); 45 | pars[n_args] = nullptr; 46 | 47 | size_t n_env = envs.size(); 48 | char **env = new char *[n_env + 1]; 49 | for(size_t i=0; i(envs.at(i).c_str()); 51 | env[n_env] = nullptr; 52 | 53 | if (execvpe(pars[0], &pars[0], env) == -1) { 54 | std::string error = myformat("CANNOT INVOKE \"%s\"!", command.c_str()); 55 | 56 | write(fd_master, error.c_str(), error.size()); 57 | 58 | error_exit(true, "Failed to invoke %s", command.c_str()); 59 | } 60 | } 61 | 62 | std::tuple out(pid, fd_master, fd_master); 63 | 64 | return out; 65 | } 66 | 67 | void run(const std::string & what) 68 | { 69 | pid_t child = fork(); 70 | if (child == -1) 71 | error_exit(true, "fork failed"); 72 | 73 | if (child == 0) { 74 | setsid(); 75 | 76 | int rc = system(what.c_str()); 77 | if (rc == 127) 78 | error_exit(false, "system(%s) failed (%d)\n", what.c_str(), rc); 79 | 80 | exit(0); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /phys_gen_ppp.h: -------------------------------------------------------------------------------- 1 | // (C) 2022-2023 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "any_addr.h" 10 | #include "network_layer.h" 11 | #include "phys.h" 12 | #include "stats.h" 13 | 14 | 15 | any_addr gen_opponent_mac(const any_addr & my_mac); 16 | 17 | std::vector unwrap_ppp_frame(const std::vector & payload, const std::vector & ACCM); 18 | 19 | class phys_gen_ppp : public phys 20 | { 21 | protected: 22 | bool protocol_compression { false }; 23 | bool ac_field_compression { false }; 24 | bool lcp_options_acked { false }; 25 | bool ipcp_options_acked { false }; 26 | bool ipv6cp_options_acked { false }; 27 | 28 | uint32_t magic { 0x1234abcd }; 29 | 30 | std::vector ACCM_tx; 31 | std::vector ACCM_rx; 32 | 33 | const any_addr opponent_address; 34 | 35 | uint16_t fcstab[256] { 0 }; 36 | 37 | void handle_lcp(const std::vector & data); 38 | void handle_ccp(const std::vector & data); 39 | void handle_ipcp(const std::vector & data); 40 | void handle_ipv6cp(const std::vector & data); 41 | 42 | void send_Xcp(const uint8_t code, const uint8_t identifier, const uint16_t protocol, const std::vector & data); 43 | void send_rej(const uint16_t protocol, const uint8_t identifier, const std::vector & options); 44 | void send_ack(const uint16_t protocol, const uint8_t identifier, const std::vector & options); 45 | void send_nak(const uint16_t protocol, const uint8_t identifier, const std::vector & options); 46 | 47 | std::vector wrap_in_ppp_frame(const std::vector & payload, const uint16_t protocol, const std::vector & ACCM, const bool not_ppp_meta); 48 | 49 | void process_incoming_packet(std::vector packet_buffer, const struct timespec & ts); 50 | 51 | virtual bool transmit_low(const std::vector & payload, const uint16_t protocol, const std::vector & ACCM, const bool not_ppp_meta) = 0; 52 | 53 | public: 54 | phys_gen_ppp(const size_t dev_index, stats *const s, const std::string & name, const any_addr & my_mac, const any_addr & opponent_address, router *const r); 55 | phys_gen_ppp(const phys_gen_ppp &) = delete; 56 | virtual ~phys_gen_ppp(); 57 | 58 | void start() override; 59 | 60 | bool transmit_packet(const any_addr & dest_mac, const any_addr & src_mac, const uint16_t ether_type, const uint8_t *payload, const size_t pl_size) override; 61 | 62 | any_addr::addr_family get_phys_type() override { return any_addr::mac; } 63 | 64 | virtual void operator()() override = 0; 65 | }; 66 | -------------------------------------------------------------------------------- /log.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "log.h" 12 | #include "time.h" 13 | #include "utils.h" 14 | 15 | 16 | static const char *logfile = strdup("/tmp/myip.log"); 17 | log_level_t log_level_file = ll_warning; 18 | log_level_t log_level_screen = ll_warning; 19 | static FILE *lfh = nullptr; 20 | static int lf_uid = 0; 21 | static int lf_gid = 0; 22 | 23 | void setlog(const char *lf, const log_level_t ll_file, const log_level_t ll_screen) 24 | { 25 | if (lfh) 26 | fclose(lfh); 27 | 28 | free((void *)logfile); 29 | 30 | logfile = strdup(lf); 31 | 32 | log_level_file = ll_file; 33 | log_level_screen = ll_screen; 34 | } 35 | 36 | void setloguid(const int uid, const int gid) 37 | { 38 | lf_uid = uid; 39 | lf_gid = gid; 40 | } 41 | 42 | void closelog() 43 | { 44 | fclose(lfh); 45 | lfh = nullptr; 46 | } 47 | 48 | void dolog(const log_level_t ll, const char *fmt, ...) 49 | { 50 | if (ll < log_level_file && ll < log_level_screen) 51 | return; 52 | 53 | if (!lfh) { 54 | lfh = fopen(logfile, "a+"); 55 | if (!lfh) { 56 | fprintf(stderr, "Cannot access log-file %s: %s\n", logfile, strerror(errno)); 57 | exit(1); 58 | } 59 | 60 | if (fchown(fileno(lfh), lf_uid, lf_gid) == -1) 61 | fprintf(stderr, "Cannot change logfile (%s) ownership: %s\n", logfile, strerror(errno)); 62 | 63 | if (fcntl(fileno(lfh), F_SETFD, FD_CLOEXEC) == -1) { 64 | fprintf(stderr, "fcntl(FD_CLOEXEC): %s\n", strerror(errno)); 65 | exit(1); 66 | } 67 | } 68 | 69 | uint64_t now = get_us(); 70 | time_t t_now = now / 1000000; 71 | 72 | struct tm tm { 0 }; 73 | if (!localtime_r(&t_now, &tm)) 74 | fprintf(stderr, "localtime_r: %s\n", strerror(errno)); 75 | 76 | char *ts_str = nullptr; 77 | 78 | const char *const ll_names[] = { "debug ", "info ", "warning", "error " }; 79 | 80 | asprintf(&ts_str, "%04d-%02d-%02d %02d:%02d:%02d.%06d %d] %s %-15s ", 81 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, int(now % 1000000), 82 | gettid(), ll_names[ll], get_thread_name().c_str()); 83 | 84 | char *str = nullptr; 85 | 86 | va_list ap; 87 | va_start(ap, fmt); 88 | (void)vasprintf(&str, fmt, ap); 89 | va_end(ap); 90 | 91 | if (ll >= log_level_file) 92 | fprintf(lfh, "%s%s", ts_str, str); 93 | 94 | if (ll >= log_level_screen) 95 | printf("%s%s", ts_str, str); 96 | 97 | free(str); 98 | free(ts_str); 99 | } 100 | -------------------------------------------------------------------------------- /buffer_out.cpp: -------------------------------------------------------------------------------- 1 | #include "buffer_out.h" 2 | 3 | buffer_out::buffer_out() 4 | { 5 | } 6 | 7 | buffer_out::~buffer_out() 8 | { 9 | } 10 | 11 | void buffer_out::add_net_byte(const uint8_t b) 12 | { 13 | buffer.push_back(b); 14 | } 15 | 16 | void buffer_out::add_net_short(const uint16_t s) 17 | { 18 | buffer.push_back(s >> 8); 19 | buffer.push_back(s); 20 | } 21 | 22 | void buffer_out::add_net_long(const uint32_t l) 23 | { 24 | buffer.push_back(l >> 24); 25 | buffer.push_back(l >> 16); 26 | buffer.push_back(l >> 8); 27 | buffer.push_back(l); 28 | } 29 | 30 | size_t buffer_out::add_net_short(const uint16_t s, const ssize_t offset) 31 | { 32 | if (offset != -1) { 33 | buffer.at(offset + 0) = s >> 8; 34 | buffer.at(offset + 1) = s; 35 | 36 | return offset; 37 | } 38 | 39 | size_t o = buffer.size(); 40 | 41 | buffer.push_back(s >> 8); 42 | buffer.push_back(s); 43 | 44 | return o; 45 | } 46 | 47 | size_t buffer_out::add_net_long(const uint32_t l, const ssize_t offset) 48 | { 49 | if (offset != -1) { 50 | buffer.at(offset + 0) = l >> 24; 51 | buffer.at(offset + 1) = l >> 16; 52 | buffer.at(offset + 2) = l >> 8; 53 | buffer.at(offset + 3) = l; 54 | 55 | return offset; 56 | } 57 | 58 | size_t o = buffer.size(); 59 | 60 | buffer.push_back(l >> 24); 61 | buffer.push_back(l >> 16); 62 | buffer.push_back(l >> 8); 63 | buffer.push_back(l); 64 | 65 | return o; 66 | } 67 | 68 | void buffer_out::add_any_addr(const any_addr & a) 69 | { 70 | int len = a.get_len(); 71 | 72 | for(int i=0; i & buffer_out::get_payload() const 107 | { 108 | return buffer; 109 | } 110 | 111 | bool buffer_out::compare(const buffer_in & b) const 112 | { 113 | return b.peek() == buffer; 114 | } 115 | 116 | size_t buffer_out::get_size() const 117 | { 118 | return buffer.size(); 119 | } 120 | 121 | const uint8_t *buffer_out::get_content() const 122 | { 123 | return buffer.data(); 124 | } 125 | -------------------------------------------------------------------------------- /phys.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2023 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "any_addr.h" 11 | #include "network_layer.h" 12 | #include "stats.h" 13 | 14 | 15 | #ifndef SIOCGSTAMPNS_OLD 16 | #define SIOCGSTAMPNS_OLD SIOCGSTAMPNS 17 | #endif 18 | 19 | class router; 20 | 21 | class phys 22 | { 23 | protected: 24 | std::thread *th { nullptr }; 25 | std::atomic_bool stop_flag { false }; 26 | 27 | uint64_t *phys_recv_frame { nullptr }; 28 | uint64_t *phys_invl_frame { nullptr }; 29 | uint64_t *phys_ign_frame { nullptr }; 30 | 31 | uint64_t *phys_ifInOctets { nullptr }; 32 | uint64_t *phys_ifHCInOctets { nullptr }; 33 | uint64_t *phys_ifInUcastPkts { nullptr }; 34 | uint64_t *phys_ifOutOctets { nullptr }; 35 | uint64_t *phys_ifHCOutOctets { nullptr }; 36 | uint64_t *phys_ifOutUcastPkts { nullptr }; 37 | 38 | int mtu_size { 0 }; 39 | 40 | router *const r; 41 | std::map prot_map; 42 | 43 | const size_t dev_index { 0 }; 44 | 45 | const std::string name; 46 | 47 | any_addr my_mac; 48 | 49 | bool SIOCGSTAMPNS_OLD_error_emitted = false; 50 | 51 | std::mutex pcap_lock; 52 | pcap_t *ph { nullptr }; 53 | pcap_dumper_t *pdh { nullptr }; 54 | bool pcap_write_incoming { false }; 55 | bool pcap_write_outgoing { false }; 56 | 57 | void pcap_write_packet_incoming(const timespec & ts, const uint8_t *const data, const size_t n); 58 | void pcap_write_packet_outgoing(const timespec & ts, const uint8_t *const data, const size_t n); 59 | 60 | public: 61 | phys(const size_t dev_index, stats *const s, const std::string & name, router *const r); 62 | phys(const phys &) = delete; 63 | virtual ~phys(); 64 | 65 | void ask_to_stop(); 66 | 67 | void start_pcap(const std::string & pcap_file, const bool in, const bool out, const uint32_t link_type); 68 | void stop_pcap(); 69 | 70 | virtual void start(); 71 | void stop(); 72 | 73 | timespec gen_packet_timestamp(const int fd); 74 | 75 | void register_protocol(const uint16_t ether_type, network_layer *const p); 76 | 77 | any_addr get_local_mac() const { return my_mac; } 78 | 79 | network_layer *get_protocol(const uint16_t p); 80 | 81 | virtual bool transmit_packet(const any_addr & dest_mac, const any_addr & src_mac, const uint16_t ether_type, const uint8_t *payload, const size_t pl_size) = 0; 82 | 83 | int get_max_packet_size() const { return mtu_size - 14 /* 14 = size of Ethernet header */; } 84 | 85 | std::string to_str() const { return name; } 86 | 87 | virtual any_addr::addr_family get_phys_type() = 0; 88 | 89 | virtual void operator()() = 0; 90 | }; 91 | -------------------------------------------------------------------------------- /snmp_data.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "snmp_elem.h" 9 | 10 | 11 | class snmp_data_type 12 | { 13 | protected: 14 | int oid_idx { 0 }; 15 | std::string oid; 16 | 17 | std::vector data; 18 | 19 | public: 20 | snmp_data_type(); 21 | virtual ~snmp_data_type(); 22 | 23 | virtual snmp_elem * get_data(); 24 | 25 | std::vector * get_children(); 26 | void set_tree_data(const std::string & oid); 27 | int get_oid_idx() const; 28 | std::string get_oid() const; 29 | }; 30 | 31 | class snmp_data_type_static : public snmp_data_type 32 | { 33 | private: 34 | const bool is_string { false }; 35 | const std::string data; 36 | const snmp_integer::snmp_integer_type type { snmp_integer::si_integer }; 37 | const int data_int { 0 }; 38 | 39 | public: 40 | snmp_data_type_static(const std::string & content); 41 | snmp_data_type_static(const snmp_integer::snmp_integer_type type, const int content); 42 | ~snmp_data_type_static(); 43 | 44 | snmp_elem * get_data() override; 45 | }; 46 | 47 | class snmp_data_type_stats : public snmp_data_type 48 | { 49 | private: 50 | const snmp_integer::snmp_integer_type type; 51 | 52 | uint64_t *const counter; 53 | 54 | public: 55 | snmp_data_type_stats(const snmp_integer::snmp_integer_type type, uint64_t *const counter); 56 | ~snmp_data_type_stats(); 57 | 58 | snmp_elem * get_data() override; 59 | }; 60 | 61 | class snmp_data_type_running_since : public snmp_data_type 62 | { 63 | private: 64 | const uint64_t running_since; 65 | 66 | public: 67 | snmp_data_type_running_since(); 68 | ~snmp_data_type_running_since(); 69 | 70 | snmp_elem * get_data() override; 71 | }; 72 | 73 | class snmp_data_type_oid : public snmp_data_type 74 | { 75 | private: 76 | const std::string oid; 77 | 78 | public: 79 | snmp_data_type_oid(const std::string & oid) : oid(oid) { 80 | } 81 | 82 | ~snmp_data_type_oid() { 83 | } 84 | 85 | snmp_elem * get_data() override { return new snmp_oid(oid); } 86 | }; 87 | 88 | class snmp_data 89 | { 90 | private: 91 | std::vector data; 92 | std::mutex lock; 93 | 94 | void walk_tree(snmp_data_type & node); 95 | 96 | public: 97 | snmp_data(); 98 | virtual ~snmp_data(); 99 | 100 | void register_oid(const std::string & oid, const std::string & static_data); 101 | void register_oid(const std::string & oid, const snmp_integer::snmp_integer_type type, const int static_data); 102 | void register_oid(const std::string & oid, snmp_data_type *const e); 103 | 104 | std::optional find_by_oid(const std::string & oid); 105 | std::string find_next_oid(const std::string & oid); 106 | 107 | void dump_tree(); 108 | }; 109 | -------------------------------------------------------------------------------- /test-node-001.cfg: -------------------------------------------------------------------------------- 1 | logging = { 2 | file="myip.log"; 3 | level_file="debug"; 4 | level_screen="debug"; 5 | } 6 | 7 | environment = { 8 | chdir-path="./" 9 | run-as=0 10 | run-in=0 11 | 12 | ifup="./test-node-001-go.sh" 13 | ifdown="./test-node-001-stop.sh" 14 | 15 | stats-socket="/tmp/myipstats.sock"; 16 | 17 | n-router-threads=4; 18 | } 19 | 20 | interfaces = ( 21 | { 22 | # either slip, ppp, udp, promiscuous (for existing interfaces), kiss (AX.25) 23 | # or tap 24 | type="kiss" 25 | 26 | # device name to connect to 27 | descriptor="pty-master:/tmp/kisstnc.lnk" 28 | 29 | # for kiss: 30 | # pty-master:dev-file create a PTY to which kissattach can connect (TNC mode) 31 | # pty-client:dev-file open an existing PTY (TNC client mode) 32 | # tty:dev-file:baudrate open a serial port on which a TNC listens 33 | # tcp-client:host:port connect to a KISS over TCP server 34 | # tcp-server:listen-addr:port listens for a KISS over TCP client 35 | # 36 | beacon = "Hello, world!"; 37 | beacon-interval=30; 38 | 39 | default-interface = true; 40 | 41 | upstream-dns = "8.8.8.8"; 42 | 43 | ipv4 = { 44 | my-address="192.168.100.2"; 45 | 46 | forwarder = true; 47 | 48 | use-icmp=true; 49 | use-tcp=true; 50 | use-udp=true; 51 | use-sctp=true; 52 | n-icmp-threads=4; 53 | n-sctp-threads=4; 54 | n-tcp-threads=4; 55 | n-udp-threads=4; 56 | } 57 | 58 | mac-address="PD9FVH-2"; 59 | 60 | routes-ax25 = ( { 61 | # callsign to route through this interface 62 | callsign = "PD9FVH-1"; 63 | ## route it via the following repeater (optional) 64 | #via-callsign = "PD9FVH-3"; 65 | } 66 | ) 67 | 68 | routes = ( { # this interface is the default 69 | ip-family = "ipv4"; 70 | network = "0.0.0.0"; 71 | netmask = "0.0.0.0"; 72 | gateway = "192.168.100.1"; 73 | priority = 0; 74 | }, 75 | { 76 | ip-family = "ipv4"; 77 | network = "192.168.100.0"; 78 | netmask = "255.255.255.0"; 79 | priority = 10; 80 | }) 81 | }, 82 | { 83 | type="kiss"; 84 | 85 | descriptor="tcp-server:0.0.0.0:8105"; 86 | 87 | #beacon = "Hello, world!"; 88 | #beacon-interval=0; in seconds 89 | 90 | default-interface = false; 91 | 92 | upstream-dns = "8.8.8.8"; 93 | 94 | ipv4 = { 95 | my-address="192.168.101.1"; 96 | 97 | use-icmp=true; 98 | use-tcp=true; 99 | use-udp=true; 100 | use-sctp=true; 101 | n-icmp-threads=4; 102 | n-sctp-threads=4; 103 | n-tcp-threads=4; 104 | n-udp-threads=4; 105 | } 106 | 107 | mac-address="PD9FVH-3"; 108 | 109 | routes = ( { # this interface is the default 110 | ip-family = "ipv4"; 111 | network = "0.0.0.0"; 112 | netmask = "0.0.0.0"; 113 | gateway = "192.168.101.1"; 114 | }, 115 | { 116 | ip-family = "ipv4"; 117 | network = "192.168.101.0"; 118 | netmask = "255.255.255.0"; 119 | }) 120 | } 121 | ) 122 | -------------------------------------------------------------------------------- /test-node-002.cfg: -------------------------------------------------------------------------------- 1 | logging = { 2 | file="myip.log"; 3 | level_file="debug"; 4 | level_screen="debug"; 5 | } 6 | 7 | environment = { 8 | chdir-path="./" 9 | run-as=0 10 | run-in=0 11 | 12 | ifup="./test-node-002-go.sh" 13 | ifdown="./test-node-002-stop.sh" 14 | 15 | stats-socket="/tmp/myipstats.sock"; 16 | 17 | n-router-threads=4; 18 | } 19 | 20 | interfaces = ( 21 | { 22 | # either slip, ppp, udp, promiscuous (for existing interfaces), kiss (AX.25) 23 | # or tap 24 | type="kiss" 25 | 26 | # device name to connect to 27 | descriptor="pty-master:/tmp/kisstnc.lnk" 28 | 29 | # for kiss: 30 | # pty-master:dev-file create a PTY to which kissattach can connect (TNC mode) 31 | # pty-client:dev-file open an existing PTY (TNC client mode) 32 | # tty:dev-file:baudrate open a serial port on which a TNC listens 33 | # tcp-client:host:port connect to a KISS over TCP server 34 | # tcp-server:listen-addr:port listens for a KISS over TCP client 35 | # 36 | beacon = "Hello, world!"; 37 | beacon-interval=30; 38 | 39 | default-interface = true; 40 | 41 | upstream-dns = "8.8.8.8"; 42 | 43 | ipv4 = { 44 | my-address="192.168.100.3"; 45 | 46 | forwarder = true; 47 | 48 | use-icmp=true; 49 | use-tcp=true; 50 | use-udp=true; 51 | use-sctp=true; 52 | n-icmp-threads=4; 53 | n-sctp-threads=4; 54 | n-tcp-threads=4; 55 | n-udp-threads=4; 56 | } 57 | 58 | mac-address="PD9FVH-4"; 59 | 60 | routes-ax25 = ( #{ 61 | # # callsign to route through this interface 62 | # callsign = "PD9FVH-1"; 63 | # ## route it via the following repeater (optional) 64 | # via-callsign = "PD9FVH-2"; 65 | # }, 66 | # { 67 | # callsign = "PD9FVH-2"; 68 | # } 69 | ) 70 | 71 | routes = ( { # this interface is the default 72 | ip-family = "ipv4"; 73 | network = "0.0.0.0"; 74 | netmask = "0.0.0.0"; 75 | gateway = "192.168.100.1"; 76 | priority = 0; 77 | }, 78 | { 79 | ip-family = "ipv4"; 80 | network = "192.168.100.0"; 81 | netmask = "255.255.255.0"; 82 | priority = 10; 83 | }) 84 | }, 85 | { 86 | type="kiss"; 87 | 88 | descriptor="tcp-client:192.168.65.101:8105"; 89 | 90 | #beacon = "Hello, world!"; 91 | #beacon-interval=0; in seconds 92 | 93 | default-interface = false; 94 | 95 | upstream-dns = "8.8.8.8"; 96 | 97 | ipv4 = { 98 | my-address="192.168.101.2"; 99 | 100 | use-icmp=true; 101 | use-tcp=true; 102 | use-udp=true; 103 | use-sctp=true; 104 | n-icmp-threads=4; 105 | n-sctp-threads=4; 106 | n-tcp-threads=4; 107 | n-udp-threads=4; 108 | } 109 | 110 | mac-address="PD9FVH-5"; 111 | 112 | routes = ( { # this interface is the default 113 | ip-family = "ipv4"; 114 | network = "0.0.0.0"; 115 | netmask = "0.0.0.0"; 116 | gateway = "192.168.101.1"; 117 | }, 118 | { 119 | ip-family = "ipv4"; 120 | network = "192.168.101.0"; 121 | netmask = "255.255.255.0"; 122 | }) 123 | } 124 | ) 125 | -------------------------------------------------------------------------------- /phys_vpn_insertion_point.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2024 by folkert van heusden , released under Apache License v2.0 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "log.h" 17 | #include "net.h" 18 | #include "phys_vpn_insertion_point.h" 19 | #include "packet.h" 20 | #include "tty.h" 21 | #include "utils.h" 22 | 23 | 24 | phys_vpn_insertion_point::phys_vpn_insertion_point(const size_t dev_index, stats *const s, const std::string & dev_name, router *const r, const any_addr & my_mac): 25 | phys(dev_index, s, "vpn-" + dev_name, r) 26 | { 27 | this->my_mac = my_mac; 28 | } 29 | 30 | phys_vpn_insertion_point::~phys_vpn_insertion_point() 31 | { 32 | } 33 | 34 | void phys_vpn_insertion_point::start() 35 | { 36 | th = new std::thread(std::ref(*this)); 37 | } 38 | 39 | void phys_vpn_insertion_point::configure_endpoint(vpn *const v) 40 | { 41 | this->v = v; 42 | } 43 | 44 | bool phys_vpn_insertion_point::transmit_packet(const any_addr & dst_mac, const any_addr & src_mac, const uint16_t ether_type, const uint8_t *payload, const size_t pl_size) 45 | { 46 | if (!v) { 47 | CDOLOG(ll_debug, "[VPN]", "not configured yet\n"); 48 | return false; 49 | } 50 | 51 | stats_add_counter(phys_ifOutOctets, pl_size); 52 | stats_add_counter(phys_ifHCOutOctets, pl_size); 53 | stats_inc_counter(phys_ifOutUcastPkts); 54 | 55 | // loopback 56 | if (dst_mac == my_mac) { 57 | CDOLOG(ll_debug, "[VPN]", "transmit (loopback!) packet %s -> %s\n", src_mac.to_str().c_str(), dst_mac.to_str().c_str()); 58 | return insert_packet(dst_mac, src_mac, ether_type, payload, pl_size); 59 | } 60 | 61 | CDOLOG(ll_debug, "[VPN]", "transmit packet %s -> %s\n", src_mac.to_str().c_str(), dst_mac.to_str().c_str()); 62 | 63 | return v->transmit_packet(dst_mac, src_mac, ether_type, payload, pl_size); 64 | } 65 | 66 | void phys_vpn_insertion_point::operator()() 67 | { 68 | // not used 69 | } 70 | 71 | bool phys_vpn_insertion_point::insert_packet(const uint16_t ether_type, const uint8_t *const payload, const size_t pl_size) 72 | { 73 | return insert_packet(gen_opponent_mac(my_mac), my_mac, ether_type, payload, pl_size); 74 | } 75 | 76 | bool phys_vpn_insertion_point::insert_packet(const any_addr & dst_mac, const any_addr & src_mac, const uint16_t ether_type, const uint8_t *const payload, const size_t pl_size) 77 | { 78 | CDOLOG(ll_debug, "[VPN]", "phys_vpn_insertion_point::insert_packet: %s -> %s\n", src_mac.to_str().c_str(), dst_mac.to_str().c_str()); 79 | 80 | timespec ts { 0, 0 }; 81 | if (clock_gettime(CLOCK_REALTIME, &ts) == -1) 82 | CDOLOG(ll_warning, "[vpn]", "clock_gettime failed: %s\n", strerror(errno)); 83 | 84 | auto it = prot_map.find(ether_type); 85 | if (it == prot_map.end()) { 86 | CDOLOG(ll_info, "[vpn]", "dropping ethernet packet with ether type %04x (= unknown) and size %zu\n", ether_type, pl_size); 87 | return false; 88 | } 89 | 90 | packet *p = new packet(ts, dst_mac, src_mac, payload, pl_size, nullptr, 0, "vpn", true); 91 | 92 | it->second->queue_incoming_packet(this, p); 93 | 94 | return true; 95 | } 96 | -------------------------------------------------------------------------------- /str.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | std::string myformat(const char *const fmt, ...) 11 | { 12 | char *buffer = nullptr; 13 | va_list ap; 14 | 15 | va_start(ap, fmt); 16 | (void)vasprintf(&buffer, fmt, ap); 17 | va_end(ap); 18 | 19 | std::string result = buffer; 20 | free(buffer); 21 | 22 | return result; 23 | } 24 | 25 | std::vector split(std::string in, std::string splitter) 26 | { 27 | std::vector out; 28 | size_t splitter_size = splitter.size(); 29 | 30 | for(;;) 31 | { 32 | size_t pos = in.find(splitter); 33 | if (pos == std::string::npos) 34 | break; 35 | 36 | std::string before = in.substr(0, pos); 37 | out.push_back(before); 38 | 39 | size_t bytes_left = in.size() - (pos + splitter_size); 40 | if (bytes_left == 0) 41 | { 42 | out.push_back(""); 43 | return out; 44 | } 45 | 46 | in = in.substr(pos + splitter_size); 47 | } 48 | 49 | if (in.size() > 0) 50 | out.push_back(in); 51 | 52 | return out; 53 | } 54 | 55 | 56 | std::string bin_to_text(const uint8_t *p, const size_t len, const bool prefer_ascii) 57 | { 58 | char *temp = (char *)calloc(1, len * 6 + 1); 59 | size_t o = 0; 60 | 61 | for(size_t i=0; i 32 && p[i] < 127) 64 | o += snprintf(&temp[o], 7, "%c", p[i]); 65 | else 66 | o += snprintf(&temp[o], 7, "[%02x]", p[i]); 67 | } 68 | else { 69 | o += snprintf(&temp[o], 7, "%s%02x", i ? " " : "", p[i]); 70 | } 71 | } 72 | 73 | std::string out = temp; 74 | 75 | free(temp); 76 | 77 | return out; 78 | } 79 | 80 | std::string str_tolower(std::string s) 81 | { 82 | std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c){ return std::tolower(c); }); 83 | 84 | return s; 85 | } 86 | 87 | std::optional find_header(const std::vector *const lines, const std::string & key, const std::string & seperator) 88 | { 89 | const std::string lkey = str_tolower(key); 90 | std::optional value; 91 | 92 | for(auto & line : *lines) { 93 | auto parts = split(line, seperator); 94 | 95 | if (parts.size() >= 2 && str_tolower(parts.at(0)) == lkey) { 96 | value = line.substr(key.size() + 1); 97 | 98 | while(value.value().empty() == false && value.value().at(0) == ' ') 99 | value = value.value().substr(1); 100 | } 101 | } 102 | 103 | return value; 104 | } 105 | 106 | std::string merge(const std::vector & in, const std::string & seperator) 107 | { 108 | std::string out; 109 | 110 | for(auto & l : in) 111 | out += l + seperator; 112 | 113 | return out; 114 | } 115 | 116 | std::string replace(std::string target, const std::string & what, const std::string & by_what) 117 | { 118 | for(;;) { 119 | std::size_t found = target.find(what); 120 | 121 | if (found == std::string::npos) 122 | break; 123 | 124 | std::string before = target.substr(0, found); 125 | 126 | std::size_t after_offset = found + what.size(); 127 | std::string after = target.substr(after_offset); 128 | 129 | target = before + by_what + after; 130 | } 131 | 132 | return target; 133 | } 134 | -------------------------------------------------------------------------------- /net.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "any_addr.h" 11 | #include "log.h" 12 | 13 | 14 | void swap_mac(uint8_t *a, uint8_t *b) 15 | { 16 | uint8_t temp[6]; 17 | memcpy(temp, a, 6); 18 | memcpy(a, b, 6); 19 | memcpy(b, temp, 6); 20 | } 21 | 22 | void swap_ipv4(uint8_t *a, uint8_t *b) 23 | { 24 | uint8_t temp[4]; 25 | memcpy(temp, a, 4); 26 | memcpy(a, b, 4); 27 | memcpy(b, temp, 4); 28 | } 29 | 30 | int create_datagram_socket(const int port) 31 | { 32 | int fd = socket(AF_INET, SOCK_DGRAM, 0); 33 | if (fd == -1) 34 | return -1; 35 | 36 | struct sockaddr_in a { 0 }; 37 | a.sin_family = PF_INET; 38 | a.sin_port = htons(port); 39 | a.sin_addr.s_addr = htonl(INADDR_ANY); 40 | 41 | if (bind(fd, reinterpret_cast(&a), sizeof(a)) == -1) { 42 | close(fd); 43 | 44 | DOLOG(ll_error, "Cannot bind to port %d: %s\n", port, strerror(errno)); 45 | 46 | return -1; 47 | } 48 | 49 | return fd; 50 | } 51 | 52 | std::optional get_host_as_text(struct sockaddr *const a) 53 | { 54 | char buffer[INET6_ADDRSTRLEN > INET_ADDRSTRLEN ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN] { 0 }; 55 | 56 | if (a->sa_family == AF_INET6) { 57 | struct sockaddr_in6 *addr_in6 = reinterpret_cast(a); 58 | 59 | if (!inet_ntop(a->sa_family, &addr_in6->sin6_addr, buffer, INET6_ADDRSTRLEN)) { 60 | DOLOG(ll_info, "Problem converting sockaddr: %s\n", strerror(errno)); 61 | 62 | return { }; 63 | } 64 | } 65 | else if (a->sa_family == AF_INET) { 66 | struct sockaddr_in *addr_in = reinterpret_cast(a); 67 | 68 | if (!inet_ntop(a->sa_family, &addr_in->sin_addr, buffer, INET_ADDRSTRLEN)) { 69 | DOLOG(ll_info, "Problem converting sockaddr: %s\n", strerror(errno)); 70 | 71 | return { }; 72 | } 73 | } 74 | else { 75 | DOLOG(ll_warning, "Unsupported address family %d\n", a->sa_family); 76 | 77 | return { }; 78 | } 79 | 80 | return buffer; 81 | } 82 | 83 | bool check_subnet(const any_addr & addr, const any_addr & network, const int cidr) 84 | { 85 | uint8_t addr_bytes[16] { 0 }; 86 | addr.get(addr_bytes, sizeof addr_bytes); 87 | 88 | uint8_t network_bytes[16] { 0 }; 89 | network.get(network_bytes, sizeof network_bytes); 90 | 91 | int n_bytes = cidr / 8; 92 | 93 | if (std::equal(addr_bytes, addr_bytes + n_bytes, network_bytes) == false) 94 | return false; 95 | 96 | int n_bits = cidr & 7; 97 | 98 | if (n_bits) { 99 | int mask = 0xff << (8 - n_bits); 100 | 101 | if ((addr_bytes[n_bytes] & mask) != (network_bytes[n_bytes] & mask)) 102 | return false; 103 | } 104 | 105 | return true; 106 | } 107 | 108 | bool check_subnet(const any_addr & addr, const any_addr & network, const uint8_t netmask[4]) 109 | { 110 | for(int i=0; i<4; i++) { 111 | if ((addr[i] & netmask[i]) != network[i]) 112 | return false; 113 | } 114 | 115 | return true; 116 | } 117 | 118 | any_addr gen_opponent_mac(const any_addr & my_mac) 119 | { 120 | uint8_t src_mac_bin[6] { 0 }; 121 | 122 | for(int i=0; i<6; i++) 123 | src_mac_bin[i] = my_mac[i] ^ ((i & 1) ? 0x55 : 0xaa); 124 | 125 | return any_addr(any_addr::mac, src_mac_bin); 126 | } 127 | -------------------------------------------------------------------------------- /echo.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2020-2023 by folkert van heusden , released under Apache License v2.0 2 | 3 | #include "application.h" 4 | #include "log.h" 5 | #include "pstream.h" 6 | #include "types.h" 7 | #include "utils.h" 8 | 9 | 10 | using namespace std::chrono_literals; 11 | 12 | void echo_init() 13 | { 14 | } 15 | 16 | void echo_deinit() 17 | { 18 | } 19 | 20 | void echo_thread(session *session_in) 21 | { 22 | set_thread_name("myip-echo"); 23 | 24 | echo_session_data *session = dynamic_cast(session_in->get_callback_private_data()); 25 | 26 | std::unique_lock lck(session->r_lock); 27 | 28 | for(;session->terminate == false;) { 29 | if (session->req_data) { 30 | session_in->get_stream_target()->send_data(session_in, session->req_data, session->req_len); 31 | 32 | free(session->req_data); 33 | 34 | session->req_data = nullptr; 35 | session->req_len = 0; 36 | } 37 | 38 | session->r_cond.wait_for(lck, 500ms); 39 | } 40 | } 41 | 42 | bool echo_new_session(pstream *const ps, session *const session) 43 | { 44 | echo_session_data *ts = new echo_session_data(); 45 | ts->req_data = nullptr; 46 | ts->req_len = 0; 47 | 48 | any_addr src_addr = session->get_their_addr(); 49 | ts->client_addr = src_addr.to_str(); 50 | 51 | session->set_callback_private_data(ts); 52 | 53 | ts->th = new std::thread(echo_thread, session); 54 | 55 | return true; 56 | } 57 | 58 | bool echo_new_data(pstream *const ps, session *const session_in, buffer_in data) 59 | { 60 | if (!session_in) { 61 | DOLOG(ll_info, "ECHO: Data for a non-existing session\n"); 62 | 63 | return false; 64 | } 65 | 66 | echo_session_data *session = dynamic_cast(session_in->get_callback_private_data()); 67 | 68 | int data_len = data.get_n_bytes_left(); 69 | 70 | if (data_len == 0) { 71 | DOLOG(ll_debug, "ECHO: client closed session\n"); 72 | 73 | return true; 74 | } 75 | 76 | const std::lock_guard lck(session->r_lock); 77 | 78 | session->req_data = reinterpret_cast(realloc(session->req_data, session->req_len + data_len + 1)); 79 | 80 | memcpy(&session->req_data[session->req_len], data.get_bytes(data_len), data_len); 81 | session->req_len += data_len; 82 | session->req_data[session->req_len] = 0x00; 83 | 84 | session->r_cond.notify_one(); 85 | 86 | return true; 87 | } 88 | 89 | bool echo_session_closed_1(pstream *const ps, session *const session) 90 | { 91 | return true; 92 | } 93 | 94 | bool echo_session_closed_2(pstream *const ps, session *const session) 95 | { 96 | session_data *sd = session->get_callback_private_data(); 97 | 98 | if (sd) { 99 | echo_session_data *esd = dynamic_cast(sd); 100 | 101 | esd->terminate = true; 102 | 103 | esd->th->join(); 104 | delete esd->th; 105 | esd->th = nullptr; 106 | 107 | free(esd->req_data); 108 | 109 | delete esd; 110 | 111 | session->set_callback_private_data(nullptr); 112 | } 113 | 114 | return true; 115 | } 116 | 117 | port_handler_t echo_get_handler() 118 | { 119 | port_handler_t meta { 0 }; 120 | 121 | meta.init = echo_init; 122 | meta.deinit = echo_deinit; 123 | meta.new_session = echo_new_session; 124 | meta.new_data = echo_new_data; 125 | meta.session_closed_1 = echo_session_closed_1; 126 | meta.session_closed_2 = echo_session_closed_2; 127 | 128 | return meta; 129 | } 130 | -------------------------------------------------------------------------------- /ax25.h: -------------------------------------------------------------------------------- 1 | // (C) 2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "any_addr.h" 12 | #include "buffer_in.h" 13 | #include "network_layer.h" 14 | #include "phys.h" 15 | #include "router.h" 16 | #include "stats.h" 17 | 18 | 19 | class ipv4; 20 | 21 | class ax25_address 22 | { 23 | private: 24 | bool valid { false }; 25 | std::string invalid_reason; 26 | std::string address; 27 | int ssid { 0 }; 28 | bool end_mark { false }; 29 | bool repeated { false }; 30 | 31 | public: 32 | ax25_address(); 33 | ax25_address(const std::vector & from); 34 | ax25_address(const any_addr & a); 35 | ax25_address(const ax25_address & a); 36 | ax25_address(const std::string & a, const int ssid, const bool end_mark, const bool repeated); 37 | ax25_address(const std::string & a, const bool end_mark, const bool repeated); 38 | 39 | ax25_address & operator=(const ax25_address &); 40 | bool operator==(const ax25_address & other) const; 41 | 42 | bool get_valid() const { return valid; } 43 | std::string get_invalid_reason() const { return invalid_reason; } 44 | 45 | bool get_end_mark() const { return end_mark; } 46 | bool get_repeated() const { return repeated; } 47 | void reset_end_mark() { end_mark = false; } 48 | void set_end_mark() { end_mark = true; } 49 | 50 | std::string get_address() const { return address; } 51 | std::string to_str() const { return address + myformat("-%d", ssid); } 52 | int get_ssid() const { return ssid; } 53 | 54 | void set_address(const std::string & address, const int ssid); 55 | 56 | std::vector generate_address() const; 57 | 58 | any_addr get_any_addr() const; 59 | }; 60 | 61 | class ax25_packet 62 | { 63 | public: 64 | enum frame_type { TYPE_I, TYPE_S, TYPE_U, TYPE_UI }; 65 | 66 | private: 67 | bool valid { false }; 68 | std::string invalid_reason; 69 | ax25_address from; 70 | ax25_address to; 71 | std::vector repeaters; 72 | uint8_t control { 0 }; 73 | frame_type type { TYPE_I }; 74 | std::optional msg_nr { }; 75 | std::optional pid { }; 76 | buffer_in data; 77 | 78 | public: 79 | ax25_packet(); 80 | ax25_packet(const std::vector & in); 81 | ~ax25_packet(); 82 | 83 | void set_from (const std::string & callsign, const int ssid, const bool end_mark, const bool repeated); 84 | void set_from (const any_addr & callsign); 85 | void set_to (const std::string & callsign, const int ssid, const bool end_mark, const bool repeated); 86 | void set_to (const any_addr & callsign); 87 | void add_repeater(const any_addr & callsign); 88 | void set_control (const uint8_t control); 89 | void set_pid (const uint8_t pid ); 90 | void set_type (const frame_type f ); 91 | void set_data (const uint8_t *const p, const size_t size); 92 | 93 | ax25_address get_from() const; 94 | ax25_address get_to () const; 95 | std::vector get_repeaters() const; 96 | buffer_in get_data() const; 97 | std::optional get_pid () const; 98 | frame_type get_type() const { return type; } 99 | bool get_valid() const { return valid; } 100 | std::string get_invalid_reason() const { return invalid_reason; } 101 | 102 | std::pair generate_packet() const; 103 | 104 | std::string to_str() const; 105 | }; 106 | -------------------------------------------------------------------------------- /buffer_in.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "buffer_in.h" 5 | 6 | 7 | uint16_t get_net_short(const uint8_t *const p) 8 | { 9 | return (p[0] << 8) | p[1]; 10 | } 11 | 12 | uint32_t get_net_long(const uint8_t *const p) 13 | { 14 | return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 15 | } 16 | 17 | uint64_t get_net_long_long(const uint8_t *const p) 18 | { 19 | uint64_t out = 0; 20 | 21 | for(int i=0; i<8; i++) { 22 | out <<= 8; 23 | out |= p[i]; 24 | } 25 | 26 | return out; 27 | } 28 | 29 | buffer_in::buffer_in() 30 | { 31 | } 32 | 33 | buffer_in::buffer_in(const uint8_t *p, const int size) : p(p), size(size) 34 | { 35 | } 36 | 37 | buffer_in::buffer_in(const buffer_in & b) : p(b.get_pointer()), size(b.get_size()) 38 | { 39 | } 40 | 41 | buffer_in::~buffer_in() 42 | { 43 | } 44 | 45 | uint8_t buffer_in::get_net_byte() 46 | { 47 | if (o >= size) 48 | throw std::out_of_range("buffer_in::get_net_byte"); 49 | 50 | return p[o++]; 51 | } 52 | 53 | uint16_t buffer_in::get_net_short() 54 | { 55 | if (o + 2 > size) 56 | throw std::out_of_range("buffer_in::get_net_short"); 57 | 58 | uint16_t temp = ::get_net_short(&p[o]); 59 | o += 2; 60 | 61 | return temp; 62 | } 63 | 64 | uint32_t buffer_in::get_net_long() 65 | { 66 | if (o + 4 > size) 67 | throw std::out_of_range("buffer_in::get_net_long"); 68 | 69 | uint32_t temp = ::get_net_long(&p[o]); 70 | o += 4; 71 | 72 | return temp; 73 | } 74 | 75 | uint64_t buffer_in::get_net_long_long() 76 | { 77 | if (o + 8 > size) 78 | throw std::out_of_range("buffer_in::get_net_long_long"); 79 | 80 | uint64_t temp = ::get_net_long_long(&p[o]); 81 | o += 8; 82 | 83 | return temp; 84 | } 85 | 86 | float buffer_in::get_net_float() 87 | { 88 | if (o + 4 > size) 89 | throw std::out_of_range("buffer_in::get_net_float"); 90 | 91 | uint32_t temp = ::get_net_long(&p[o]); 92 | o += 4; 93 | 94 | return *reinterpret_cast(&temp); 95 | } 96 | 97 | double buffer_in::get_net_double() 98 | { 99 | if (o + 8 > size) 100 | throw std::out_of_range("buffer_in::get_net_double"); 101 | 102 | uint64_t temp = ::get_net_long_long(&p[o]); 103 | o += 8; 104 | 105 | return *reinterpret_cast(&temp); 106 | } 107 | 108 | buffer_in buffer_in::get_segment(const int len) 109 | { 110 | if (o + len > size) 111 | throw std::out_of_range("buffer_in::get_segment"); 112 | 113 | buffer_in temp = buffer_in(&p[o], len); 114 | o += len; 115 | 116 | return temp; 117 | } 118 | 119 | std::string buffer_in::get_string(const int len) 120 | { 121 | if (o + len > size) 122 | throw std::out_of_range("buffer_in::get_segment"); 123 | 124 | std::string temp = std::string(reinterpret_cast(&p[o]), len); 125 | o += len; 126 | 127 | return temp; 128 | } 129 | 130 | void buffer_in::seek(const int len) 131 | { 132 | if (o + len > size) 133 | throw std::out_of_range("buffer_in::seek"); 134 | 135 | o += len; 136 | } 137 | 138 | bool buffer_in::end_reached() const 139 | { 140 | return o == size; 141 | } 142 | 143 | int buffer_in::get_n_bytes_left() const 144 | { 145 | return size - o; 146 | } 147 | 148 | const std::vector buffer_in::peek() const 149 | { 150 | return std::vector(&p[o], &p[size]); 151 | } 152 | 153 | const uint8_t *buffer_in::get_bytes(const int len) const 154 | { 155 | if (o + len > size) 156 | throw std::out_of_range("buffer_in::get_bytes"); 157 | 158 | int temp = o; 159 | o += len; 160 | 161 | return &p[temp]; 162 | } 163 | 164 | uint64_t get_variable_size_integer(buffer_in & data_source, const int len) 165 | { 166 | uint64_t out = 0; 167 | 168 | for(int i=0; i 4 | # Licensed under the Apache License v2.0 5 | 6 | import copy 7 | import socket 8 | 9 | port_tcp_listening = 13 # 'daytime' service 10 | port_tcp_not_listening = 29889 # should trigger 'connection refused' 11 | 12 | def checksum(data): 13 | chksum = 0 14 | 15 | for idx in range(0, len(data), 2): 16 | word = (data[idx] << 8) | data[idx + 1] 17 | 18 | chksum += word 19 | 20 | chksum = (chksum >> 16) + (chksum & 0xffff) 21 | chksum += (chksum >> 16) 22 | chksum = (~chksum) & 0xffff 23 | 24 | return chksum 25 | 26 | def mac_to_str(mac): 27 | return f'{mac[0]:02x} {mac[1]:02x} {mac[2]:02x} {mac[3]:02x} {mac[4]:02x} {mac[5]:02x}' 28 | 29 | def ipv4_addr_to_str(addr): 30 | return f'{addr[0]}.{addr[1]}.{addr[2]}.{addr[3]}' 31 | 32 | def get_uint16(data): 33 | return (data[0] << 8) | data[1] 34 | 35 | def get_uint32(data): 36 | return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3] 37 | 38 | def open_netdev(dev_name): 39 | fd = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003)) as sock: 40 | 41 | fd.bind((dev_name, 0)) 42 | 43 | return fd 44 | 45 | fd = open_netdev('myip') 46 | 47 | while True: 48 | raw_packet = bytearray(sock.recv(9000)) 49 | 50 | if len(raw_packet) & 1: 51 | raw_packet += bytearray([ 0 ]) 52 | 53 | packet_type = get_uint16(raw_packet[12:14]) 54 | 55 | print(f'from: {mac_to_str(raw_packet[0:6])} to: {mac_to_str(raw_packet[6:12])} type: {packet_type:04x}') 56 | 57 | payload = raw_packet[14:] 58 | 59 | if packet_type == 0x0800: # IPv4 60 | version = payload[0] >> 4 61 | if version != 4: 62 | print('Mismatch between Ethertype and IP-header version field for IPv4 packet') 63 | 64 | ihl = payload[0] & 0x0f 65 | 66 | if ihl < 5: 67 | print(f'IPv4 header too short, must be at least 20 (5 fields): {ihl}') 68 | 69 | ip_header = payload[0: ihl * 4] # TODO: check size 70 | 71 | # verify header checksum 72 | ipv4_checksum = get_uint16(payload[10:12]) 73 | 74 | ip_header_copy = copy.deepcopy(ip_header) 75 | ip_header_copy[10] = ip_header_copy[11] = 0 76 | 77 | ip_calc_checksum = checksum(ip_header_copy) 78 | 79 | if ip_calc_checksum != ipv4_checksum: 80 | print(f'IPv4 header checksum {ipv4_checksum:04x} incorrect, should be: {ip_calc_checksum:04x}') 81 | 82 | # evaluate protocol (layer 6) 83 | protocol = ip_header[9] 84 | 85 | if protocol == 17: # UDP 86 | udp_data = payload[ihl * 4:] 87 | 88 | ## verify checksum 89 | udp_checksum = get_uint16(udp_data[6:8]) 90 | 91 | udp_length = get_uint16(udp_data[4:6]) 92 | 93 | # create IPv4 pseudo header 94 | udp_header_copy = copy.deepcopy(udp_data[0:8]) 95 | udp_header_copy[6] = udp_header_copy[7] = 0x00 96 | 97 | pseudo_header = ip_header[12:16] + ip_header[16:20] + bytearray([ 0x00, protocol ]) + bytearray([ udp_length >> 8, udp_length & 255]) + udp_header_copy + udp_data[8:] 98 | 99 | if len(pseudo_header) & 1: 100 | print(f'Pseudo header is odd in size {len(pseudo_header)}') 101 | 102 | assert len(pseudo_header) == 12 + len(udp_data) 103 | 104 | udp_calc_checksum = checksum(pseudo_header) 105 | 106 | if udp_calc_checksum != udp_checksum: 107 | print(f'{ipv4_addr_to_str(ip_header[12:16])} -> {ipv4_addr_to_str(ip_header[16:20])}') 108 | print(f'UDP header checksum {udp_checksum:04x} incorrect, should be: {udp_calc_checksum:04x}') 109 | -------------------------------------------------------------------------------- /router.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "log.h" 11 | #include "stats.h" 12 | #include "utils.h" 13 | 14 | 15 | class arp; 16 | class ndp; 17 | class phys; 18 | 19 | class router 20 | { 21 | private: 22 | class ip_router_entry { 23 | public: 24 | any_addr local_ip; 25 | 26 | any_addr network_address; 27 | 28 | union { 29 | uint8_t ipv4_netmask[4]; 30 | 31 | int ipv6_prefix_length; 32 | } mask; 33 | 34 | int priority { -1 }; 35 | 36 | phys *interface; 37 | 38 | union { 39 | arp *iarp; 40 | ndp *indp; 41 | } mac_lookup; 42 | 43 | std::optional default_gateway; 44 | 45 | std::string to_str(); 46 | }; 47 | 48 | class ax25_router_entry { 49 | public: 50 | std::optional interface; 51 | std::optional via; 52 | 53 | std::string to_str(); 54 | }; 55 | 56 | std::shared_mutex table_lock; 57 | std::vector ip_table; 58 | std::map ax25_table; 59 | 60 | phys *ax25_default_interface { nullptr }; 61 | 62 | class queued_packet { 63 | public: 64 | std::optional dst_mac; 65 | std::optional src_mac; 66 | 67 | uint16_t ether_type { 0 }; 68 | 69 | std::optional dst_ip; 70 | std::optional src_ip; 71 | 72 | std::optional interface; 73 | 74 | uint8_t *data { nullptr }; 75 | size_t data_len { 0 }; 76 | 77 | queued_packet(const uint8_t *const data, const size_t data_len) { 78 | this->data = duplicate(data, data_len); 79 | this->data_len = data_len; 80 | } 81 | 82 | ~queued_packet() { 83 | delete [] data; 84 | } 85 | 86 | std::string to_str() { 87 | std::string dst_mac_str = dst_mac.has_value() ? dst_mac.value().to_str() : ""; 88 | std::string src_mac_str = src_mac.has_value() ? src_mac.value().to_str() : ""; 89 | 90 | if (ether_type == 0x08FF) 91 | return src_mac_str + " -> " + dst_mac_str; 92 | 93 | return src_ip.value().to_str() + " (" + src_mac_str + ") -> " + dst_ip.value().to_str() + " (" + dst_mac_str + ")"; 94 | } 95 | }; 96 | 97 | fifo *pkts { nullptr }; 98 | 99 | std::vector router_ths; 100 | 101 | std::atomic_bool stop_flag { false }; 102 | 103 | ip_router_entry *find_route(const std::optional & mac, const any_addr & ip); 104 | 105 | std::optional > resolve_mac_by_addr(ip_router_entry *const re, const any_addr & addr); 106 | std::optional find_interface_by_mac(ip_router_entry *const re, const any_addr & addr); 107 | 108 | public: 109 | router(stats *const s, const int n_threads); 110 | virtual ~router(); 111 | 112 | void stop(); 113 | 114 | void set_default_ax25_interface(phys *const ax25_default_interface) { this->ax25_default_interface = ax25_default_interface; } 115 | 116 | void add_ax25_route(const any_addr & callsign, std::optional interface, std::optional via); 117 | void add_router_ipv4(const any_addr & local_ip, const any_addr & network, const uint8_t netmask[4], const std::optional & gateway, const int priority, phys *const interface, arp *const iarp); 118 | void add_router_ipv6(const any_addr & local_ip, const any_addr & network, const int cidr, const int priority, phys *const interface, ndp *const indp); 119 | 120 | bool route_packet(const std::optional & override_dst_mac, const uint16_t ether_type, const any_addr & dst_ip, const std::optional & src_mac, const any_addr & src_ip, const uint8_t *const payload, const size_t pl_size); 121 | 122 | void dump(); 123 | 124 | void operator()(); 125 | }; 126 | -------------------------------------------------------------------------------- /test-http.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | import random 4 | import socket 5 | import string 6 | 7 | def weighted_rand_0_10(): 8 | return random.choices([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], weights=[10, 9, 8, 7, 6, 5, 4, 3, 2, 1])[0] 9 | 10 | def gen_url(relative): 11 | assert relative # absolute not implemented yet TODO 12 | 13 | url = '' 14 | 15 | if random.choice([False, True]): 16 | for i in range(0, weighted_rand_0_10()): 17 | url += '\\' if random.choices([False, True], weights=[90, 10])[0] else '/' 18 | 19 | for i in range(0, 32): 20 | c = random.choices([random.randint(0, 33), random.randint(33, 127), random.randint(127, 256)], weights=[5, 95, 5])[0] 21 | 22 | url += f'%{c:02x}' if (c < 32 or c > 126) and random.choices([False, True], weights=[5, 95])[0] else chr(c) 23 | 24 | if random.choice([False, True]): 25 | url += '.' + random.choice(['html', 'htm', 'php', 'php3', 'cgi', 'jpg', 'jpeg', 'png']) 26 | 27 | return url 28 | 29 | def gen_http_prot(): 30 | 31 | if random.choices([False, True], weights=[10, 90])[0]: 32 | return f'HTTP/{weighted_rand_0_10()}.{weighted_rand_0_10()}' 33 | 34 | return f'HTTP/{weighted_rand_0_10()}' 35 | 36 | def gen_eol(): 37 | return random.choices(['\r\n', '\n', '\r', '\n\r', '', ' '], 38 | weights=[50 , 10 , 10 , 10 , 10, 10 ])[0] 39 | 40 | def gen_space(swap_w): 41 | if random.choices([False, True], weights=([90, 10] if swap_w else [10, 90]))[0]: 42 | return '' 43 | 44 | return random.choices([' ', '\t'], weights=[80, 20])[0] * random.randint(1, 3) 45 | 46 | def gen_ascii(): 47 | a = '' 48 | 49 | for i in range(1, 128): 50 | a += random.choice(string.ascii_letters) 51 | 52 | return a 53 | 54 | while True: 55 | request = '' 56 | 57 | for i in range(0, 100): 58 | if i == 0: 59 | method = random.choice(['GET', 'POST', 'HEAD']) 60 | sp1 = gen_space(True) 61 | sp2 = gen_space(True) 62 | url = gen_url(True) 63 | prot = gen_http_prot() 64 | eol = gen_eol() 65 | 66 | request += f'{method}{sp1}{url}{sp2}{prot}{eol}' 67 | 68 | else: 69 | k = gen_ascii() if random.choices([False, True], weights=[10, 90])[0] else '' 70 | v = gen_ascii() if random.choices([False, True], weights=[10, 90])[0] else '' 71 | colon = ':' if random.choices([False, True], weights=[10, 90])[0] else '' 72 | sp1 = gen_space(False) 73 | sp2 = gen_space(False) 74 | eol = gen_eol() 75 | 76 | request += f'{k}{sp1}{colon}{sp2}{v}{eol}' 77 | 78 | request += gen_eol() 79 | 80 | # TODO: casing fuzzer 81 | 82 | print(request) 83 | 84 | try: 85 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 86 | 87 | s.settimeout(5.0) 88 | 89 | s.connect(('192.168.3.2', 80)) 90 | 91 | b = request.encode('ascii', 'ignore') 92 | 93 | if random.choices([False, True], weights=[10, 90])[0]: 94 | s.send(request.encode('ascii', 'ignore')) 95 | 96 | elif len(b) > 0: 97 | s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) 98 | s.setsockopt(socket.IPPROTO_TCP, socket.TCP_CORK, 1) 99 | 100 | while True: 101 | b_len = len(b) 102 | 103 | if b_len == 0: 104 | break 105 | 106 | cur_len = random.randint(1, b_len + 1) 107 | 108 | s.send(b[0:cur_len]) 109 | 110 | b = b[cur_len:] 111 | 112 | s.close() 113 | 114 | except OSError as oe: 115 | print(f' *** Timeout: {oe} ***') 116 | -------------------------------------------------------------------------------- /stats.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "log.h" 12 | #include "stats.h" 13 | #include "stats_utils.h" 14 | 15 | 16 | constexpr char shm_name[] = "/myip"; 17 | 18 | void stats_inc_counter(uint64_t *const p) 19 | { 20 | #if defined(GCC_VERSION) && GCC_VERSION >= 40700 21 | __atomic_add_fetch(p, 1, __ATOMIC_SEQ_CST); 22 | #else 23 | (*p)++; // hope for the best 24 | #endif 25 | } 26 | 27 | void stats_add_counter(uint64_t *const p, const uint64_t value) 28 | { 29 | #if defined(GCC_VERSION) && GCC_VERSION >= 40700 30 | __atomic_add_fetch(p, value, __ATOMIC_SEQ_CST); 31 | #else 32 | (*p) += value; // hope for the best 33 | #endif 34 | } 35 | 36 | void stats_set(uint64_t *const p, const uint64_t value) 37 | { 38 | #if defined(GCC_VERSION) && GCC_VERSION >= 40700 39 | __atomic_store(p, &value, __ATOMIC_SEQ_CST); 40 | #else 41 | *p = value; // hope for the best 42 | #endif 43 | } 44 | 45 | void stats_add_average(uint64_t *const p, const int val) 46 | { 47 | #if defined(GCC_VERSION) && GCC_VERSION >= 40700 48 | // there's a window where the values are 49 | // not in sync 50 | __atomic_add_fetch(p + 1, 1, __ATOMIC_SEQ_CST); 51 | __atomic_add_fetch(p, val, __ATOMIC_SEQ_CST); 52 | #else 53 | // hope for the best 54 | (*(p + 1))++; 55 | (*p) += val; 56 | #endif 57 | } 58 | 59 | stats::stats(const int size, snmp_data *const sd) : 60 | size(size), 61 | sd(sd) 62 | { 63 | fd = shm_open(shm_name, O_RDWR | O_CREAT, 0644); 64 | if (fd == -1) { 65 | DOLOG(ll_error, "shm_open: %s", strerror(errno)); 66 | exit(1); 67 | } 68 | 69 | if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { 70 | DOLOG(ll_error, "fcntl(FD_CLOEXEC): %s", strerror(errno)); 71 | exit(1); 72 | } 73 | 74 | if (ftruncate(fd, size) == -1) { 75 | DOLOG(ll_error, "truncate: %s", strerror(errno)); 76 | exit(1); 77 | } 78 | 79 | p = (uint8_t *)mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 80 | if (p == MAP_FAILED) { 81 | DOLOG(ll_error, "mmap: %s", strerror(errno)); 82 | exit(1); 83 | } 84 | 85 | memset(p, 0x00, size); 86 | 87 | close(fd); 88 | } 89 | 90 | stats::~stats() 91 | { 92 | DOLOG(ll_debug, "Removing shared memory segment\n"); 93 | munmap(p, size); 94 | 95 | shm_unlink(shm_name); 96 | } 97 | 98 | uint64_t * stats::register_stat(const std::string & name, const std::string & oid, const snmp_integer::snmp_integer_type type) 99 | { 100 | if (len + 48 > size) { 101 | DOLOG(ll_error, "stats: shm is full\n"); 102 | return nullptr; 103 | } 104 | 105 | std::unique_lock lck(lock); 106 | 107 | uint8_t *p_out = (uint8_t *)&p[len]; 108 | 109 | // hopefully this platform allows atomic updates 110 | // not using locking, for speed 111 | *(uint64_t *)p_out = 0; 112 | *(uint64_t *)(p_out + 8) = 0; 113 | 114 | int copy_n = std::min(name.size(), size_t(31)); 115 | memcpy(&p_out[16], name.c_str(), copy_n); 116 | p_out[16 + copy_n] = 0x00; 117 | 118 | len += 48; 119 | 120 | if (oid.empty() == false) 121 | sd->register_oid(oid, new snmp_data_type_stats(type, reinterpret_cast(p_out))); 122 | 123 | return reinterpret_cast(p_out); 124 | } 125 | 126 | void stats::register_fifo_stats(const std::string & name, fifo_stats *const fs) 127 | { 128 | std::unique_lock lck(lock); 129 | 130 | this->fs.insert({ name, fs }); 131 | } 132 | 133 | std::string stats::to_json() const 134 | { 135 | return stats_to_json(p, get_fifo_stats(), size); 136 | } 137 | 138 | std::vector > stats::get_fifo_stats() const 139 | { 140 | std::vector > out; 141 | 142 | std::unique_lock lck(lock); 143 | 144 | for(auto & item : fs) 145 | out.push_back({ item.first, item.second }); 146 | 147 | return out; 148 | } 149 | -------------------------------------------------------------------------------- /lldp.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2022 by folkert van heusden , released under Apache License v2.0 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "lldp.h" 10 | #include "log.h" 11 | #include "phys.h" 12 | #include "router.h" 13 | #include "time.h" 14 | #include "utils.h" 15 | 16 | 17 | lldp::lldp(stats *const s, const any_addr & my_mac, const any_addr & mgmt_addr, const int interface_idx, router *const r) : network_layer(s, "lldp", r), my_mac(my_mac), mgmt_addr(mgmt_addr), interface_idx(interface_idx) 18 | { 19 | th = new std::thread(std::ref(*this)); 20 | } 21 | 22 | lldp::~lldp() 23 | { 24 | stop_flag.signal_stop(); 25 | 26 | th->join(); 27 | delete th; 28 | } 29 | 30 | bool lldp::transmit_packet(const std::optional & dst_mac, const any_addr & dst_ip, const any_addr & src_ip, const uint8_t protocol, const uint8_t *payload, const size_t pl_size, const uint8_t *const header_template) 31 | { 32 | assert(0); 33 | 34 | return false; 35 | } 36 | 37 | void lldp::queue_incoming_packet(phys *const interface, packet *p) 38 | { 39 | delete p; 40 | } 41 | 42 | void lldp::add_tlv(std::vector *const target, const uint8_t type, const std::vector & payload) 43 | { 44 | uint16_t header = (type << 9) | payload.size(); 45 | target->push_back(header >> 8); 46 | target->push_back(header); 47 | 48 | std::copy(payload.begin(), payload.end(), std::back_inserter(*target)); 49 | } 50 | 51 | std::vector str_to_uvec(const std::string & in) 52 | { 53 | std::vector out; 54 | 55 | for(size_t i=0; i lldp::generate_lldp_packet() 62 | { 63 | std::vector out; 64 | 65 | // CHASSIS ID 66 | std::vector chassis_id { 4 }; // mac adress 67 | for(int i=0; i<6; i++) 68 | chassis_id.push_back(my_mac[i]); 69 | add_tlv(&out, 1, chassis_id); 70 | 71 | // PORT ID 72 | std::vector port_id { 3 }; // mac adress 73 | for(int i=0; i<6; i++) 74 | port_id.push_back(my_mac[i]); 75 | add_tlv(&out, 2, port_id); 76 | 77 | // TTL 78 | std::vector ttl; 79 | ttl.push_back(0); 80 | ttl.push_back(30); // 30s 81 | add_tlv(&out, 3, ttl); 82 | 83 | // SYSTEM DESCRIPTION 84 | std::string description = "MyIP - www.vanheusden.com"; 85 | std::vector system_description = str_to_uvec(description); 86 | add_tlv(&out, 6, system_description); 87 | 88 | // CAPABILITIES 89 | uint16_t capabilities = 0x01 /* other */ | 0x10 /* router */ | 0x80 /* station */; 90 | std::vector caps; 91 | caps.push_back(capabilities >> 8); 92 | caps.push_back(capabilities); 93 | caps.push_back(0); // reserved 94 | caps.push_back(0); 95 | add_tlv(&out, 7, caps); 96 | 97 | // MANAGEMENT ADDRESS 98 | std::vector mgmt; 99 | 100 | mgmt.push_back(1 + mgmt_addr.get_len()); // the address 101 | mgmt.push_back(mgmt_addr.get_len() == 4 ? 1 : 6); // '6' is a guess (for IPv6) 102 | for(int i=0; i> 24); 107 | mgmt.push_back(interface_idx >> 16); 108 | mgmt.push_back(interface_idx >> 8); 109 | mgmt.push_back(interface_idx); 110 | mgmt.push_back(0); // oid string length 111 | 112 | add_tlv(&out, 8, mgmt); 113 | 114 | // end marker 115 | add_tlv(&out, 0, { }); 116 | 117 | return out; 118 | } 119 | 120 | void lldp::operator()() 121 | { 122 | set_thread_name("myip-lldp"); 123 | 124 | any_addr dest_mac(any_addr::mac, std::initializer_list({ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }).begin()); 125 | auto payload = generate_lldp_packet(); 126 | 127 | for(;;) { 128 | if (stop_flag.sleep(15000)) 129 | break; 130 | 131 | // every 15s 132 | if (default_pdev) { 133 | DOLOG(ll_debug, "lldp::operator: transmit LLDP packet\n"); 134 | 135 | default_pdev->transmit_packet(dest_mac, my_mac, 0x88cc, payload.data(), payload.size()); 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /www/default/key.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | 3 | mQINBGQPfWEBEADHi7Sb4tGM35dFe1eE0vl1Hel7nvyR2lkzueUh3uv5YoECt5aH 4 | ifKgd05ZqOHCkFFaIhb4ZF0ak74418StFVHjd0cXfwgrswpZi3896sC9o3lPEw54 5 | /y3KvRoUaMCDXam/nSU3Td1jzOMKQgeVrtgt9wsG0bAJMHANEvjJFZV2jq2XpKAG 6 | s4hv94NRoikszqgxGspAG9ttFPrHYm8t1NPNkI56pvt0geBiY2hzZsa7q8g3oXz9 7 | IkYqt2X2TofJkaFv7ZyHTLi/lILwfb/24wPZn4eQGAplWDnc+6dbt0dnGCSmed2l 8 | Jlf1exTZTw743YzEkZthzeky52nYmGIIUZQzM02oiS5iF/Wmz+2V2FRvS6RCSXwT 9 | 3+bdalCKZl24aabS0TPNNh2etQK4AoRc6KGXKx/L1/YOpg91WZl0Ny/r/CYBJOHO 10 | Qg84jH8jVJbUmgi79f9oSIUOSZEmkT5KGcIg/JaoUlWo0ru/OJcqAzqdkDs+UnmF 11 | GYYAeZLXkheqFem7MoVi5ihZhE3avie+3xMzfjO+kQu/DgMOukX5h5qkD282WtbA 12 | b8VIdp/FddHxFgyJXpYKCbM455DxQTM5Rwd9W8ilWNy0iwYVB7LPN+mI/2g1kZGY 13 | VYgZkPoymJbKAWcAFaJKYNXedX2wWxMFcYWuLjkn0KjknnXSoMWYAAAgDwARAQAB 14 | tClGb2xrZXJ0IHZhbiBIZXVzZGVuIDxtYWlsQHZhbmhldXNkZW4uY29tPokCTgQT 15 | AQoAOBYhBEQlP49DJAUmwZ2wk2tkVe3+7TvRBQJkD31hAhsDBQsJCAcCBhUKCQgL 16 | AgQWAgMBAh4BAheAAAoJEGtkVe3+7TvRmP8P/1eNl0iobHCE3mNze6jgQwyDK7St 17 | GorsoHPyhgBiXMPaZUew3ftwK244N0hLCI1+j88MYs13Az0YESj21CcXHtYM4/HC 18 | lOl9rPdtemFjcJPDzpoZol/5rO5A8PlWK9p/G+YmaMQGuFZEEO3MZ4ogD56ECqcx 19 | WOxGabKHtcdc1Ri9R9T2yeRzL9UXFdrnJteDI9wCALhaEfo3QEw9XHG3+IBwsqwQ 20 | 8WS4d5lDR4orCck+ZHQMO+qkxkzQnz6Vh3bC7B6ZKcaGXbRC6gZQLv9eekJWVyJc 21 | VMKjkwM910e66k2fmqqmkRj1LE9a8jYBJ8Xr9UEQ4IlIROm+oUuLqZP2+PyciTze 22 | VY9sEfjyHJ9iirSO6dtiWUn/u6qihvKJs0n1lfdDasdzKBjtsR3O8i4sI3TBhnTs 23 | qRIKcENu4d9y6fyjSnBRxmMbnY3aLaK51zY00+kK7ypa6b6hTcqnSYx6UaiQkzqk 24 | YA81pMar1wH5CvdV4hV+pQBA+z69rEzms7r+t7FEnlkNjcQhUilqztam08RFSmFq 25 | 1bz3XDmvTbcsl9LGgoLIMUWXOsWUyXBPyTwnquQlLl8K7PGo4TosIhlUT8VPXPYW 26 | 2pSRVFwW4GupXoZ7JJqYI4Oe5Uu7cUWJRG33dLbh5lVJCDyGU2JKSk+0LBnA6Zsb 27 | RINKylrsTwL6vE0JtC9Gb2xrZXJ0IHZhbiBIZXVzZGVuIDxpbmZvQGhhY2tlcnNw 28 | YWNlLWdvdWRhLm5sPokCTgQTAQoAOBYhBEQlP49DJAUmwZ2wk2tkVe3+7TvRBQJk 29 | D41YAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEGtkVe3+7TvRdpEP/iJS 30 | M7iLH5XfxfgvnJ/YxPz8bgy9cstZWdjSgy3mAiYyCTFxIDIOhyt5q0VSrBwjh7mk 31 | p7UYl7NB+CcizcYXRZ4aKeBUbzramFE+9eefiyi/9JTTuG0CVnnBVb8snDYUqs2K 32 | XRoX/SiHrE6hg862XynuYBVTf9N2dg58H4UWjh2UgSXHXDSLEvkiFyGawrGSwRr3 33 | yZQf4+VVmZiFXGc4EA1A+o6K9Kt8CAxPzcoZ3XsSFDG1tvMlRN35c3YyzJwIeDZN 34 | YR8PT3plE9FKxSMfnFO7aiuYPXNl40ZFOfvmlpsQV7nkWPaAUPZsXnIn2EQGBHSq 35 | EGSRB6vrtOu9fmDmeNShpIDR/GF8smHYC3uTf2hWJhDGzFq0M8S3CgeOBAoqTbaQ 36 | 8HM43pEvN2LAvuno0CPfodhqI0igTRf/9/S6Zuz0SEEvacbSLluW6KpA8EptfiXG 37 | GR4g2VnZKrL2nSIMMsXZHQI4bE76gj85vrNi0P31Bi42bc1uwSzhLAcJiTMJIO9I 38 | T5yaIC0h8dtuRfFU0GAtZk75aAJiFL7qbcxHcUOyW3ACjlPhS/2v2xD86Y5OTxYB 39 | aICY1h+aYqXr4mb25XK8IaDsuZ5s7d2vJrqlz7HNEKWcjzW2AwRrqWl0ysi2uI2r 40 | 8nAkte2IVjfi8XNZbQsT4+8xebtPrYLVj+T0tcvIuQINBGQPfWEBEAC35KNEQznI 41 | 2jwwvM+1VCyXoDdNvIk95rZVxdXlOcPlXXIk2uSyb4+N43Mt0CbYDzYNjpgMJvQA 42 | tPZ1yu1rl6uukKYK1vgtXLGUdGnZuEZyARRA4LuM8+txgXt8DHpan67Idv4g2wlB 43 | mMdqnhZgzcOLkrMVv38ECStgiql6dBYcBGk+1JfykvVef9QlzIhhvg2dlRsnZXAE 44 | 3hesYG4dKWCTg3ezYW63OPm3yntAYPYiodO9WFVMirJXJxTWRuvOoPPNeyUY70ec 45 | qe4vAdVuC2L14vcKwcBTg2STzeHm68iyBNmAqAIUYRPmfW1jm9fZHHLVJHEBrADz 46 | ZbOrWdRZxlB8Weg1XbN/9/G8xTUH/NWl59geTO1i/Q5KsSaVZ8Y7IoZMEiX+zgxK 47 | ZRypZAd6DHPpDKE8jRiODT9YWoxBqoKvGaoUAomnIrjuKfUb4VKXJiZtzXmJSEyU 48 | MEfU52Z0rBJlP99TKT4YLuCqH8yc1QF71h5QiLuKyFO2O10MO2lK6vi743cIuB8y 49 | UvBLTRXIsSNfjCDjme8042s3HQvuKqwS7Jh4b+PSeC9CbUHfIakBcpoOoxujfk4d 50 | G4m7EJw9JsbohUf1CrX+BNW9o6Q9FjZGLUykixI5puDHmBaFtk1swzxcNiryaJDN 51 | heID3zk0KJGkY/VotFQg7pn4CUDNXPtFaQARAQABiQI2BBgBCgAgFiEERCU/j0Mk 52 | BSbBnbCTa2RV7f7tO9EFAmQPfWECGwwACgkQa2RV7f7tO9FNqhAApqTFQv7rg0Vw 53 | XLCV5NZthub9yjSXUv5/2IikzJ8nK0oWlUPpyVxqx7QsWtgc1cbWizdcmv779hdb 54 | 9MCa4W/Se1uoUoAFFusy1ixGMMIwmxwh4ksHQcyMpUeml/tP98MSM1Uf6neZ/CG8 55 | SzomAaSlAJfmeWDhsaidqTiQVrYopQAdPVieRkcnJImVRnt9irczP841uyERGHVz 56 | AYqJd4KuFv2EZBiHLuYuBU+0AJ/NgvpfU8y4jIZyeECrDD4w4woQiAcJGDW+DQy7 57 | /WSYQ8KPR8z7+KZcJlwymFWMA14D6lnhydV00nhmOMBGTnGPIWsnaO44Yc70m4rL 58 | LP94Z/08Emm4jM1lkBl+5TsfNAxLi79rJ2pYXwV7xAMU9Z7pNdIot/hxqRUw60Uo 59 | f3ko7kAZOGHcZFu7MZyHJWxyZlVyZw9IagdbGRvaEs17IcizPoWHyIKno01cuoui 60 | 54uulCBf9dpDvV3HlfYl9dTmLWWgGByZgSn0e9XRNsmfDd7PxzCcw2zJ08ZoJ/a6 61 | /8LoswbEPuI/YjtG1ZZje2EdWIZDpwDlGW5TueQvywDErTiKOlHg3BQL1ar0/RNA 62 | oTOYwnwAIcfNZA4sP2EdVc5JTKGufCC9T5gP7BFF2kCxNCE88uxVxpHeHR/hRQqP 63 | gWXwr1w7RvYKySL6ApUAMu6i9n1R6DY= 64 | =Khsb 65 | -----END PGP PUBLIC KEY BLOCK----- 66 | -------------------------------------------------------------------------------- /sip.h: -------------------------------------------------------------------------------- 1 | // (C) 2020-2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "any_addr.h" 13 | #include "application.h" 14 | #include "stats.h" 15 | #include "types.h" 16 | 17 | class packet; 18 | class udp; 19 | 20 | typedef struct { 21 | uint8_t id; 22 | std::string name, org_name; 23 | int rate; 24 | int frame_size; 25 | } codec_t; 26 | 27 | class sip_session_data : public session_data 28 | { 29 | public: 30 | uint64_t start_ts { 0 }; 31 | std::atomic_bool finished { false }; 32 | 33 | any_addr sip_addr_peer; 34 | any_addr sip_addr_me; 35 | 36 | std::vector headers; 37 | int sip_port_peer { 0 }; 38 | int sip_port_me { 0 }; 39 | 40 | std::thread *recorder { nullptr }; 41 | codec_t schema { 255, "", "", -1 }; 42 | SNDFILE *sf { nullptr }; 43 | bool stats_done { false }; 44 | 45 | std::atomic_uint64_t latest_pkt { 0 }; 46 | 47 | sip_session_data() { 48 | } 49 | }; 50 | 51 | class sip : public application 52 | { 53 | private: 54 | udp *const u; 55 | 56 | const std::string mailbox_path, mb_recv_exec; 57 | 58 | const std::string upstream_server, username, password; 59 | const any_addr myip; 60 | const int myport, interval; 61 | 62 | std::thread *th { nullptr }; 63 | std::thread *th2 { nullptr }; // register thread 64 | 65 | std::map sessions; 66 | std::mutex slock; 67 | 68 | uint64_t ddos_protection { 0 }; 69 | 70 | int samplerate { 0 }, n_samples { 0 }; 71 | short *samples { nullptr }; 72 | 73 | uint64_t *sip_requests { nullptr }; 74 | uint64_t *sip_requests_unk { nullptr }; 75 | uint64_t *sip_rtp_sessions { nullptr }; 76 | uint64_t *sip_rtp_codec_8 { nullptr }; 77 | uint64_t *sip_rtp_codec_11 { nullptr }; 78 | uint64_t *sip_rtp_codec_97 { nullptr }; 79 | uint64_t *sip_rtp_duration { nullptr }; 80 | 81 | void reply_to_OPTIONS(const any_addr & src_ip, const int src_port, const any_addr & dst_ip, const int dst_port, const std::vector *const headers); 82 | void reply_to_INVITE(const any_addr & src_ip, const int src_port, const any_addr & dst_ip, const int dst_port, const std::vector *const headers, const std::vector *const body, session_data *const pd); 83 | void voicemailbox(const any_addr & tgt_addr, const int tgt_port, const any_addr & src_addr, const int src_port, sip_session_data *const ss, session_data *const pd); 84 | void send_BYE(const any_addr & tgt_addr, const int tgt_port, const any_addr & src_addr, const int src_port, const std::vector & headers); 85 | void transmit_audio(const any_addr & tgt_addr, const int tgt_port, const any_addr & src_addr, const int src_port, sip_session_data *const ss, const short *const samples, const int n_samples, uint16_t *const seq_nr, uint32_t *const t, const uint32_t ssrc); 86 | bool send_REGISTER(const std::string & call_id, const std::string & authorize); 87 | void register_thread(); 88 | void reply_to_UNAUTHORIZED(const any_addr & src_ip, const int src_port, const any_addr & dst_ip, const int dst_port, const std::vector *const headers, session_data *const pd); 89 | void send_ACK(const any_addr & src_ip, const int src_port, const any_addr & dst_ip, const int dst_port, const std::vector *const headers, session_data *const pd); 90 | 91 | public: 92 | sip(stats *const s, udp *const u, const std::string & sample, const std::string & mailbox_path, const std::string & mb_recv_exec, const std::string & upstream_sip_server, const std::string & upstream_sip_user, const std::string & upstream_sip_password, const any_addr & myip, const int myport, const int interval); 93 | sip(const sip &) = delete; 94 | virtual ~sip(); 95 | 96 | void input(const any_addr & src_ip, int src_port, const any_addr & dst_ip, int dst_port, packet *p, session_data *const pd); 97 | 98 | void input_recv(const any_addr & src_ip, int src_port, const any_addr & dst_ip, int dst_port, packet *p, session_data *const pd); 99 | 100 | void operator()(); 101 | }; 102 | -------------------------------------------------------------------------------- /example.cfg: -------------------------------------------------------------------------------- 1 | logging = { 2 | file="/home/folkert/myip.log"; 3 | level_file="debug"; 4 | level_screen="debug"; 5 | } 6 | 7 | environment = { 8 | chdir-path="/tmp" 9 | run-as=0 10 | run-in=0 11 | 12 | #ifup= 13 | #ifdown= 14 | 15 | stats-socket="/tmp/myipstats.sock"; 16 | 17 | n-router-threads=2; 18 | } 19 | 20 | # one can have multiple network interfaces 21 | interfaces = ( { 22 | # either slip, ppp, udp, promiscuous (for existing interfaces), kiss (IP(v4) 23 | # over AX.25) or tap 24 | type="tap" 25 | 26 | # device name (ethernet) 27 | dev-name="myip" 28 | 29 | mtu-size=1520; 30 | 31 | # for kiss: 32 | # descriptor="..."; 33 | # pty-master:dev-file create a PTY to which kissattach can connect (TNC mode) 34 | # pty-client:dev-file open an existing PTY (TNC client mode) 35 | # tty:dev-file:baudrate open a serial port on which a TNC listens 36 | # tcp-client:host:port connect to a KISS over TCP server 37 | # tcp-server:listen-addr:port listens for a KISS over TCP client 38 | # 39 | #beacon = "Hello, world!"; 40 | #beacon-interval=0; in seconds 41 | 42 | enable-lldp = false 43 | 44 | n-ipv4-threads = 4; 45 | 46 | ipv4 = { 47 | my-address="192.168.3.2"; 48 | 49 | # act as a router? 50 | forwarder = false; 51 | 52 | use-icmp=true; 53 | use-tcp=true; 54 | use-udp=true; 55 | use-sctp=true; 56 | n-icmp-threads=1; 57 | n-sctp-threads=1; 58 | n-tcp-threads=8; 59 | n-udp-threads=8; 60 | } 61 | 62 | mac-address="52:34:84:16:44:22"; 63 | 64 | n-ipv6-threads = 4; 65 | 66 | ipv6 = { 67 | my-address="2001:980:c324:4242:f588:20f4:4d4e:7c2d"; 68 | 69 | use-icmp=true; 70 | use-tcp=true; 71 | use-udp=true; 72 | use-sctp=true; 73 | n-icmp-threads=1; 74 | n-sctp-threads=1; 75 | n-tcp-threads=8; 76 | n-udp-threads=8; 77 | } 78 | 79 | upstream-dns = "172.29.0.1"; 80 | 81 | routes = ( { # this interface is the default 82 | ip-family = "ipv4"; 83 | network = "0.0.0.0"; 84 | netmask = "0.0.0.0"; 85 | gateway = "192.168.3.1"; 86 | }, 87 | { 88 | ip-family = "ipv4"; 89 | network = "192.168.3.0"; 90 | netmask = "255.255.255.0"; 91 | } ) 92 | }, 93 | { 94 | type="udp" 95 | 96 | port=9899; 97 | 98 | n-ipv4-threads = 4; 99 | 100 | ipv4 = { 101 | my-address="192.168.2.2"; 102 | 103 | use-icmp=true; 104 | use-tcp=true; 105 | use-udp=true; 106 | use-sctp=true; 107 | n-icmp-threads=1; 108 | n-sctp-threads=1; 109 | n-tcp-threads=8; 110 | n-udp-threads=8; 111 | } 112 | 113 | mac-address="01:01:01:01:01:04"; 114 | 115 | n-ipv6-threads = 4; 116 | 117 | ipv6 = { 118 | my-address="2001:980:c324:4242:f588:20f4:4d4e:7c2e"; 119 | 120 | use-icmp=true; 121 | use-tcp=true; 122 | use-udp=true; 123 | use-sctp=true; 124 | n-icmp-threads=1; 125 | n-sctp-threads=1; 126 | n-tcp-threads=8; 127 | n-udp-threads=8; 128 | } 129 | 130 | routes = ( 131 | { 132 | ip-family = "ipv4"; 133 | network = "192.168.2.0"; 134 | netmask = "255.255.255.0"; 135 | } ) 136 | } 137 | ) 138 | 139 | ntp = { 140 | upstream-ip-address="192.168.64.1"; 141 | port=123; 142 | broadcast=true; 143 | } 144 | 145 | http = { 146 | web-root="/home/folkert/Projects/myip/www"; 147 | web-logfile="/home/folkert/temp/http_access.log"; 148 | port=80; 149 | mdns="somehost._http._tcp.local."; 150 | php-cgi="/usr/bin/php-cgi"; 151 | } 152 | 153 | https = { 154 | web-root="/home/folkert/Projects/myip/www"; 155 | web-logfile="/home/folkert/temp/http_access.log"; 156 | port=443; 157 | is_https=true; 158 | private-key="/home/folkert/Projects/myip/my-key.key"; 159 | certificate="/home/folkert/Projects/myip/cert.crt"; 160 | mdns="somehost._https._tcp.local."; 161 | php-cgi="/usr/bin/php-cgi"; 162 | } 163 | 164 | nrpe = { 165 | port=5666; 166 | } 167 | 168 | vnc = { 169 | port=5900; 170 | bind-to-ip-address="192.168.3.2"; 171 | } 172 | 173 | mqtt = { 174 | port=1883; 175 | } 176 | 177 | sip = { 178 | sample="/home/folkert/Projects/myip/test.wav"; 179 | mb-path="/home/folkert/temp"; 180 | mb-recv-script="/home/folkert/Projects/myip/mb-recv.sh"; 181 | upstream-sip-server="192.168.64.1"; 182 | upstream-sip-user="1234"; 183 | upstream-sip-password="1234"; 184 | sip-register-interval=15; 185 | port=5060; 186 | } 187 | 188 | snmp = { 189 | port=161; 190 | } 191 | 192 | syslog = { 193 | port=514; 194 | } 195 | -------------------------------------------------------------------------------- /phys_ppp.cpp: -------------------------------------------------------------------------------- 1 | // (C) 2022-2023 by folkert van heusden , released under Apache License v2.0 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "log.h" 16 | #include "packet.h" 17 | #include "phys_ppp.h" 18 | #include "str.h" 19 | #include "tty.h" 20 | #include "utils.h" 21 | 22 | 23 | phys_ppp::phys_ppp(const size_t dev_index, stats *const s, const std::string & dev_name, const int bps, const any_addr & my_mac, const bool emulate_modem_xp, const any_addr & opponent_address, router *const r) : 24 | phys_gen_ppp(dev_index, s, dev_name, my_mac, opponent_address, r), 25 | emulate_modem_xp(emulate_modem_xp) 26 | { 27 | fd = open_tty(dev_name, bps); 28 | } 29 | 30 | phys_ppp::~phys_ppp() 31 | { 32 | close(fd); 33 | } 34 | 35 | bool phys_ppp::transmit_low(const std::vector & payload, const uint16_t protocol, const std::vector & ACCM, const bool not_ppp_meta) 36 | { 37 | bool ok = true; 38 | 39 | std::vector out_wrapped = wrap_in_ppp_frame(payload, protocol, ACCM, not_ppp_meta); 40 | 41 | send_lock.lock(); 42 | int rc = WRITE(fd, out_wrapped.data(), out_wrapped.size()); 43 | send_lock.unlock(); 44 | 45 | if (size_t(rc) != out_wrapped.size()) { 46 | CDOLOG(ll_error, "[ppp]", "problem sending packet (%d for %zu bytes): %s\n", rc, out_wrapped.size(), strerror(errno)); 47 | 48 | if (rc == -1) 49 | CDOLOG(ll_error, "%s\n", strerror(errno)); 50 | 51 | ok = false; 52 | } 53 | 54 | return ok; 55 | } 56 | 57 | void phys_ppp::operator()() 58 | { 59 | CDOLOG(ll_debug, "[ppp]", "thread started\n"); 60 | 61 | set_thread_name("myip-phys_ppp"); 62 | 63 | std::vector packet_buffer; 64 | 65 | std::string modem; 66 | bool modem_7e_flag = false; 67 | 68 | struct pollfd fds[] = { { fd, POLLIN, 0 } }; 69 | 70 | struct timespec ts { 0, 0 }; 71 | 72 | while(!stop_flag) { 73 | int rc = poll(fds, 1, 150); 74 | if (rc == -1) { 75 | if (errno == EINTR) 76 | continue; 77 | 78 | CDOLOG(ll_error, "[ppp]", "poll: %s", strerror(errno)); 79 | exit(1); 80 | } 81 | 82 | if (rc == 0) 83 | continue; 84 | 85 | uint8_t buffer = 0x00; 86 | int size = read(fd, (char *)&buffer, 1); 87 | if (size == -1) 88 | continue; 89 | 90 | if (buffer == 0x7e) { 91 | if (packet_buffer.empty() == false) { // START/END of packet 92 | CDOLOG(ll_error, "[ppp]", "received ppp frame\n"); 93 | 94 | auto unwrapped = unwrap_ppp_frame(packet_buffer, ACCM_rx); 95 | 96 | stats_add_counter(phys_ifInOctets, unwrapped.size()); 97 | stats_add_counter(phys_ifHCInOctets, unwrapped.size()); 98 | stats_inc_counter(phys_ifInUcastPkts); 99 | 100 | process_incoming_packet(unwrapped, ts); 101 | 102 | packet_buffer.clear(); 103 | 104 | modem_7e_flag = false; 105 | modem.clear(); 106 | 107 | ts = { 0, 0 }; 108 | } 109 | else { // start of packet 110 | if (clock_gettime(CLOCK_REALTIME, &ts) == -1) 111 | CDOLOG(ll_warning, "[ppp]", "clock_gettime failed: %s", strerror(errno)); 112 | } 113 | } 114 | else { 115 | packet_buffer.push_back(buffer); 116 | 117 | if (buffer == 0x7e) 118 | modem_7e_flag = true; 119 | 120 | if (emulate_modem_xp && modem_7e_flag == false) { 121 | if ((buffer >= 32 && buffer < 127) || buffer == 10 || buffer == 13) { 122 | modem += (char)buffer; 123 | 124 | if (modem.find("ATDT") != std::string::npos) { 125 | CDOLOG(ll_debug, "[ppp]", "ATDT -> CONNECT (%s)\n", modem.c_str()); 126 | write(fd, "CONNECT\r\n", 9); 127 | modem.clear(); 128 | } 129 | else if (modem.find("AT") != std::string::npos) { 130 | CDOLOG(ll_debug, "[ppp]", "AT -> OK (%s)\n", modem.c_str()); 131 | write(fd, "OK\r\n", 4); 132 | modem.clear(); 133 | } 134 | else if (modem.find("CLIENT") != std::string::npos) { 135 | // Windows XP direction PPP connection 136 | CDOLOG(ll_debug, "[ppp]", "CLIENT -> SERVER\n"); 137 | write(fd, "SERVER\r\n", 7); 138 | modem.clear(); 139 | } 140 | } 141 | } 142 | } 143 | } 144 | 145 | CDOLOG(ll_info, "[ppp]", "thread stopped\n"); 146 | } 147 | -------------------------------------------------------------------------------- /sctp.h: -------------------------------------------------------------------------------- 1 | // (C) 2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "application.h" 9 | #include "buffer_in.h" 10 | #include "buffer_out.h" 11 | #include "hash.h" 12 | #include "transport_layer.h" 13 | #include "packet.h" 14 | #include "pstream.h" 15 | #include "session.h" 16 | 17 | 18 | class icmp; 19 | 20 | // dcb: data-call-back 21 | typedef enum { dcb_close, dcb_abort, dcb_continue } sctp_data_handling_result_t; 22 | 23 | class sctp : public transport_layer, public pstream 24 | { 25 | public: 26 | class sctp_session : public session { 27 | private: 28 | uint32_t my_tsn { 0 }; 29 | uint32_t their_tsn { 0 }; 30 | uint16_t my_stream_sequence_nr { 0 }; 31 | uint32_t their_verification_tag { 0 }; 32 | 33 | public: 34 | sctp_session(pstream *const ps, const any_addr & their_addr, const uint16_t their_port, const any_addr & my_addr, const uint16_t my_port, const uint32_t their_tsn, const uint32_t my_tsn, const uint32_t their_verification_tag, private_data *const pd) : 35 | session(ps, my_addr, my_port, their_addr, their_port, pd), 36 | my_tsn(my_tsn), their_tsn(their_tsn), 37 | their_verification_tag(their_verification_tag) 38 | { 39 | } 40 | 41 | virtual ~sctp_session() { 42 | } 43 | 44 | uint32_t get_my_tsn() const { 45 | return my_tsn; 46 | } 47 | 48 | void inc_my_tsn(const uint32_t how_much) { 49 | my_tsn += how_much; 50 | } 51 | 52 | uint32_t get_their_tsn() const { 53 | return their_tsn; 54 | } 55 | 56 | void inc_their_tsn(const uint32_t how_much) { 57 | their_tsn += how_much; 58 | } 59 | 60 | uint16_t get_my_stream_sequence_nr() const { 61 | return my_stream_sequence_nr; 62 | } 63 | 64 | void inc_my_stream_sequence_nr() { 65 | my_stream_sequence_nr++; 66 | } 67 | 68 | uint32_t get_their_verification_tag() const { 69 | return their_verification_tag; 70 | } 71 | 72 | std::string get_state_name() const { 73 | return "established"; 74 | } 75 | }; 76 | 77 | private: 78 | std::shared_mutex sessions_lock; 79 | std::map sessions; 80 | 81 | uint8_t state_cookie_key[32] { 0 }; 82 | time_t state_cookie_key_timestamp { 0 }; 83 | 84 | icmp *const icmp_; 85 | 86 | std::shared_mutex listeners_lock; 87 | std::map listeners; 88 | 89 | uint64_t *sctp_msgs { nullptr }; 90 | uint64_t *sctp_failed_msgs { nullptr }; 91 | 92 | std::pair get_parameter(const uint64_t hash, buffer_in & chunk_payload); 93 | 94 | buffer_out generate_state_cookie(const any_addr & their_addr, const int their_port, const int local_port, const uint32_t my_verification_tag, const uint32_t their_initial_tsn, const uint32_t my_initial_tsn); 95 | buffer_out chunk_gen_abort(); 96 | buffer_out chunk_gen_cookie_ack(); 97 | buffer_out chunk_gen_shutdown(); 98 | buffer_out chunk_heartbeat_request(buffer_in & chunk_payload); 99 | 100 | void chunk_init(const uint64_t hash, buffer_in & chunk_payload, const uint32_t my_verification_tag, const uint32_t buffer_size, const any_addr & their_addr, const int their_port, const int local_port, buffer_out *const out, uint32_t *const initiate_tag); 101 | void chunk_cookie_echo(buffer_in & chunk_payload, const any_addr & their_addr, const int their_port, const int local_port, bool *const ok, uint32_t *const my_verification_tag, uint32_t *const their_initial_tsn, uint32_t *const my_initial_tsn); 102 | std::pair chunk_data(sctp_session *const s, buffer_in & chunk, buffer_out *const reply, std::function & new_data_handler); 103 | 104 | bool transmit_packet(const any_addr & dst_ip, const any_addr & src_ip, const uint8_t *payload, const size_t pl_size); 105 | 106 | public: 107 | sctp(stats *const s, icmp *const icmp_, const int n_threads); 108 | virtual ~sctp(); 109 | 110 | json_t *get_state_json(session *const ts) override; 111 | 112 | void add_handler(const int port, port_handler_t & sph); 113 | 114 | bool send_data(session *const s, buffer_in & payload); 115 | bool send_data(session *const s, const uint8_t *const data, const size_t len) override; 116 | 117 | void end_session(session *const ts) override; 118 | 119 | virtual void operator()() override; 120 | }; 121 | -------------------------------------------------------------------------------- /mynetperf-client.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python3 2 | 3 | import getopt 4 | import json 5 | import math 6 | import socket 7 | import sys 8 | import time 9 | 10 | 11 | host = '192.168.3.2' 12 | port = 55201 13 | 14 | mode = None 15 | 16 | n_todo = None 17 | 18 | json_results = False 19 | 20 | work_bs = 65536 21 | 22 | opts, args = getopt.getopt(sys.argv[1:], 'H:p:b:m:n:jh') 23 | 24 | for o, a in opts: 25 | if o == '-H': 26 | host = a 27 | 28 | elif o == '-p': 29 | port = int(a) 30 | 31 | elif o == '-b': 32 | work_bs = int(a) 33 | 34 | elif o == '-m': 35 | mode = True if a == 'send' else False 36 | 37 | elif o == '-n': 38 | n_todo = int(a) 39 | 40 | elif o == '-j': 41 | json_results = True 42 | 43 | elif o == '-h': 44 | print('-H x host') 45 | print('-p x port (default: 55201)') 46 | print('-b x block size (default: %d)' % work_bs) 47 | print('-m x mode: send or receive') 48 | print('-n x limit to x exchanges') 49 | print('-j only print results in json format') 50 | sys.exit(0) 51 | 52 | if not json_results: 53 | print('send mode' if mode else 'receive mode') 54 | 55 | work = bytearray(work_bs) 56 | 57 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 58 | s.connect((host, port)) 59 | s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True) 60 | 61 | def recv_reply(s: socket) -> str: 62 | reply = '' 63 | 64 | while True: 65 | c = s.recv(1).decode('ascii') 66 | 67 | if c == '\n': 68 | break 69 | 70 | reply += c 71 | 72 | return reply 73 | 74 | min_speed = math.inf 75 | max_speed = -math.inf 76 | n = 0 77 | total = 0 78 | median = [] 79 | 80 | try: 81 | if mode: 82 | while n_todo is None or n < n_todo: 83 | bs = work_bs 84 | 85 | command = { "mode": "receive", "block_size": bs } 86 | s.send(json.dumps(command).encode('ascii')) 87 | s.send('\n'.encode('ascii')) 88 | 89 | if json.loads(recv_reply(s))['result'] != 'ok': 90 | break 91 | 92 | while bs > 0: 93 | cur_bs = min(bs, len(work)) 94 | 95 | s.send(work[0:cur_bs]) 96 | 97 | bs -= cur_bs 98 | 99 | j = json.loads(recv_reply(s)) 100 | 101 | speed = work_bs * 1000000 / j['took'] / 1024 102 | 103 | median.append(speed) 104 | 105 | total += speed 106 | n += 1 107 | 108 | min_speed = min(min_speed, speed) 109 | max_speed = max(max_speed, speed) 110 | 111 | if not json_results: 112 | print(j, f"{math.floor(speed)} kB/s") 113 | 114 | else: 115 | while n_todo is None or n < n_todo: 116 | command = { "mode": "send", "block_size": work_bs } 117 | s.send(json.dumps(command).encode('ascii')) 118 | s.send('\n'.encode('ascii')) 119 | 120 | if json.loads(recv_reply(s))['result'] != 'ok': 121 | break 122 | 123 | start_ts = time.time() 124 | 125 | bs = work_bs 126 | 127 | while bs > 0: 128 | bs -= len(s.recv(bs)) 129 | 130 | end_ts = time.time() 131 | 132 | j = json.loads(recv_reply(s)) 133 | 134 | took = end_ts - start_ts 135 | 136 | speed = work_bs / (took * 1024) 137 | 138 | median.append(speed) 139 | 140 | total += speed 141 | n += 1 142 | 143 | min_speed = min(min_speed, speed) 144 | max_speed = max(max_speed, speed) 145 | 146 | if not json_results: 147 | print(f"{math.floor(speed)} kB/s") 148 | 149 | 150 | except KeyboardInterrupt as ki: 151 | pass 152 | 153 | if not json_results: 154 | print() 155 | 156 | if n > 0: 157 | median.sort() 158 | 159 | median_val = median[n // 2] if (n & 1) else (median[n // 2] + median[n // 2 + 1]) / 2 160 | 161 | if json_results: 162 | results = { 163 | 'n': n, 164 | 'average': total / n * 1024, 165 | 'median': median_val * 1024, 166 | 'min': min_speed * 1024, 167 | 'max': max_speed * 1024, 168 | 'units': 'bytes', 169 | 'block-size': work_bs 170 | } 171 | 172 | print(json.dumps(results)) 173 | 174 | else: 175 | print(f"{n} transfers, average: {total/n:.3f} kB/s, median: {median_val:.3f} kB/s, minimum: {min_speed:.0f} kB/s, maximum: {max_speed:.0f} kB/s") 176 | -------------------------------------------------------------------------------- /fifo.h: -------------------------------------------------------------------------------- 1 | // (C) 2022 by folkert van heusden , released under Apache License v2.0 2 | #pragma once 3 | #include 4 | #include 5 | #include 6 | 7 | #include "fifo_stats.h" 8 | #include "stats.h" 9 | 10 | template 11 | class fifo 12 | { 13 | private: 14 | T *data { nullptr }; 15 | const int n_elements { 0 }; 16 | 17 | int read_pointer { 0 }; 18 | int write_pointer { 0 }; 19 | bool full { false }; 20 | 21 | bool interrupted { false }; 22 | 23 | pthread_mutex_t lock; 24 | 25 | /* cond_push is signalled when a new item is pushed 26 | * cond_pull is signalled when an item is removed 27 | */ 28 | pthread_cond_t cond_push; 29 | pthread_cond_t cond_pull; 30 | 31 | fifo_stats *fs { nullptr }; 32 | uint64_t n_in { 0 }; 33 | 34 | uint64_t *fifo_n_in_stats { nullptr }; 35 | uint64_t *fifo_full_count { nullptr }; 36 | 37 | public: 38 | fifo(stats *const s, const std::string & name, const int n_elements) : n_elements(n_elements) 39 | { 40 | data = new T[n_elements]; 41 | 42 | fifo_n_in_stats = s->register_stat(name + "_n_in"); 43 | fifo_full_count = s->register_stat(name + "_full"); 44 | 45 | fs = new fifo_stats(n_elements); 46 | s->register_fifo_stats(name, fs); 47 | 48 | pthread_mutex_init(&lock, NULL); 49 | 50 | pthread_cond_init(&cond_push, NULL); 51 | pthread_cond_init(&cond_pull, NULL); 52 | } 53 | 54 | ~fifo() 55 | { 56 | delete fs; 57 | 58 | delete [] data; 59 | } 60 | 61 | void interrupt() 62 | { 63 | pthread_mutex_lock(&lock); 64 | 65 | interrupted = true; 66 | 67 | pthread_cond_broadcast(&cond_push); 68 | 69 | pthread_mutex_unlock(&lock); 70 | } 71 | 72 | void put(const T & element) 73 | { 74 | pthread_mutex_lock(&lock); 75 | 76 | if (full) 77 | stats_inc_counter(fifo_full_count); 78 | 79 | while(full) 80 | pthread_cond_wait(&cond_pull, &lock); 81 | 82 | data[write_pointer] = element; 83 | 84 | write_pointer++; 85 | write_pointer %= n_elements; 86 | 87 | n_in++; 88 | 89 | fs->count(n_in); 90 | 91 | stats_set(fifo_n_in_stats, n_in); 92 | 93 | full = write_pointer == read_pointer; 94 | 95 | pthread_cond_signal(&cond_push); 96 | 97 | pthread_mutex_unlock(&lock); 98 | } 99 | 100 | bool try_put(const T & element) 101 | { 102 | bool have_put = false; 103 | 104 | pthread_mutex_lock(&lock); 105 | 106 | if (full) 107 | stats_inc_counter(fifo_full_count); 108 | else { 109 | data[write_pointer] = element; 110 | 111 | write_pointer++; 112 | write_pointer %= n_elements; 113 | 114 | n_in++; 115 | 116 | fs->count(n_in); 117 | 118 | stats_set(fifo_n_in_stats, n_in); 119 | 120 | full = write_pointer == read_pointer; 121 | 122 | have_put = true; 123 | 124 | pthread_cond_signal(&cond_push); 125 | } 126 | 127 | pthread_mutex_unlock(&lock); 128 | 129 | return have_put; 130 | } 131 | 132 | std::optional get(const int ms) 133 | { 134 | struct timespec ts { 0, 0 }; 135 | clock_gettime(CLOCK_REALTIME, &ts); 136 | 137 | ts.tv_nsec += (ms % 1000) * 1000000ll; 138 | ts.tv_sec += ms / 1000; 139 | 140 | if (ts.tv_nsec >= 1000000000ll) { 141 | ts.tv_nsec -= 1000000000ll; 142 | ts.tv_sec++; 143 | } 144 | 145 | pthread_mutex_lock(&lock); 146 | 147 | bool ok = true; 148 | 149 | while(read_pointer == write_pointer && !full && !interrupted) { 150 | if (pthread_cond_timedwait(&cond_push, &lock, &ts)) { 151 | ok = false; 152 | break; 153 | } 154 | } 155 | 156 | if (interrupted) { 157 | pthread_mutex_unlock(&lock); 158 | 159 | return { }; 160 | } 161 | 162 | if (ok) { 163 | T copy = data[read_pointer]; 164 | 165 | read_pointer++; 166 | read_pointer %= n_elements; 167 | 168 | n_in--; 169 | 170 | full = 0; 171 | 172 | pthread_cond_signal(&cond_pull); 173 | 174 | pthread_mutex_unlock(&lock); 175 | 176 | return copy; 177 | } 178 | 179 | pthread_mutex_unlock(&lock); 180 | 181 | return { }; 182 | } 183 | 184 | std::optional get() 185 | { 186 | pthread_mutex_lock(&lock); 187 | 188 | while(read_pointer == write_pointer && !full && !interrupted) 189 | pthread_cond_wait(&cond_push, &lock); 190 | 191 | if (interrupted) { 192 | pthread_mutex_unlock(&lock); 193 | 194 | return { }; 195 | } 196 | 197 | T copy = data[read_pointer]; 198 | 199 | read_pointer++; 200 | read_pointer %= n_elements; 201 | 202 | n_in--; 203 | 204 | full = 0; 205 | 206 | pthread_cond_signal(&cond_pull); 207 | 208 | pthread_mutex_unlock(&lock); 209 | 210 | return copy; 211 | } 212 | }; 213 | --------------------------------------------------------------------------------