├── .gitignore ├── .sonarcloud.properties ├── .travis.yml ├── BUILD.md ├── Dockerfile ├── FAQ.md ├── LICENSE.md ├── Makefile ├── Makefile.mac ├── README.md ├── VPN.md ├── bitbucket-pipelines.yml ├── cJSON.c ├── cJSON.h ├── client.c ├── client.h ├── debian ├── README.Debian ├── README.source ├── changelog ├── control ├── copyright ├── manpage.1.ex ├── manpage.sgml.ex ├── manpage.xml.ex ├── postinst.ex ├── postrm.ex ├── preinst.ex ├── prerm.ex ├── rules ├── salsa-ci.yml.ex ├── source │ └── format ├── tuntox-docs.docs ├── tuntox.cron.d.ex ├── tuntox.doc-base.EX └── watch.ex ├── freebsd ├── Makefile ├── README.md ├── distinfo └── pkg-descr ├── generate_tox_bootstrap.py ├── gitversion.c ├── gitversion.h ├── log.c ├── log.h ├── mach.h ├── main.c ├── main.h ├── multiarch-build.sh ├── screenshots └── wsl.png ├── scripts ├── docker-compose.yaml ├── pre-push.sh ├── tokssh ├── tuntox.conf ├── tuntox.debian-init └── tuntox.service ├── tox_bootstrap.h ├── tox_bootstrap_json.c ├── tox_bootstrap_json.h ├── utarray.h ├── uthash.h ├── util.c ├── util.h ├── utlist.h └── utstring.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # tuntox related, not needed in repo 32 | tuntox 33 | -------------------------------------------------------------------------------- /.sonarcloud.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gjedeer/tuntox/824babaac32c22f6c72a9eba5c54917eb8464ef7/.sonarcloud.properties -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | sudo: required 3 | dist: focal 4 | 5 | before_script: 6 | #installing libsodium, needed for Core 7 | - git clone git://github.com/jedisct1/libsodium.git > /dev/null 8 | - cd libsodium 9 | - git checkout tags/1.0.15 > /dev/null 10 | - ./autogen.sh > /dev/null 11 | - ./configure > /dev/null 12 | - make check -j3 > /dev/null 13 | - sudo make install >/dev/null 14 | - cd .. 15 | 16 | #installing yasm, needed for compiling vpx 17 | - sudo apt-get install yasm > /dev/null 18 | #creating libraries links and updating cache 19 | - sudo ldconfig > /dev/null 20 | #installing check, needed for unit tests 21 | - sudo apt-get install check cmake cscope python3-requests python3-jinja2 cscope libevent-dev libevent-pthreads-2.1 22 | - cd .. 23 | # toxcore 24 | - git clone https://github.com/TokTok/c-toxcore.git 25 | - cd c-toxcore 26 | - cmake . -DBUILD_TOXAV=OFF 27 | - make -j3 28 | - sudo make install 29 | - sudo ldconfig 30 | - cd .. 31 | - pushd . 32 | 33 | script: 34 | - popd 35 | - cd tuntox 36 | - find .. -name Makefile 37 | - make tuntox_nostatic 38 | 39 | env: 40 | global: 41 | # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created 42 | # via the "travis encrypt" command using the project repo's public key 43 | - secure: "VjQmHxt7StKi1XF45IaYei3/0GtpIjeCeySLCPyHYnSlTMYw1VWti9Pow2Vr7mses27KddWhgl54hYjukaqyNFklfz+cXuke+VSwLp/wKlC7hV+frsrodWCd35hvNDZV3Q49e1u0944Oz4ggiS1yX1+dlXZO/v6HINXouSJbbk/0UowW4T6vkD5x/Muq7ddf5J9qMr6XF7oGzZO/fHnWO4B+xILiWs3R6gk24B8IksHiHEDIsruGnbSx2OUvoYiyNOW9hVczf2DIMZVKhqWxCX7/dEs2E5K4+/pbGfww4JhbGUMtkkGk97a7Y8rdXhs1l+k5IbG9MoZ5MxcyE1t8DRJSiT8SI50AUzDZGpU7YKIRWFxj9hyIlxPuv9aL3AyhGDzHCLAUGCtV0LYWuXUKusfQ3YuWoc/Z+6I9tIDBUdGtPp8R+P7x2pHnq08PQecBgGh+KOj2rkJBv3jP5GTrH7OtjwdKQyggni+otL/0ydq9Cj67sbt2jerjlBWtI4Vg2jVbRwIT2jDcUCMwrL5kCkuXiSvywlvA/qLVIkAvLILdbIXFBUYh/N4z00YiiVhpbc3AkJaiuhDtese272nXPeYTw6qtQnZyoud3jQjWpGmsD7uYstbnRNYsmYWf4Nz2+XIJtAmqHBhRYuq50Q1ImPY2cJyo0yZ6tniSKCcqHRI=" 44 | 45 | addons: 46 | coverity_scan: 47 | project: 48 | name: "gjedeer/tuntox" 49 | description: "Build submitted via Travis CI" 50 | notification_email: gdr@gdr.name 51 | build_command_prepend: "cd tuntox; make clean" 52 | build_command: "make" 53 | branch_pattern: master 54 | 55 | -------------------------------------------------------------------------------- /BUILD.md: -------------------------------------------------------------------------------- 1 | * Install c-toxcore (libtoxav and the DNS client are not required) https://github.com/TokTok/c-toxcore/blob/master/INSTALL.md#build-manually 2 | * git clone https://github.com/gjedeer/tuntox.git 3 | * cd tuntox 4 | * make 5 | 6 | The makefile creates a static binary by default. If you're not a fan of static binaries, `make tuntox_nostatic`. 7 | 8 | One reason to do so may be if you'd like to resolve hostnames on the tuntox server (invoke client with `-L 80:reddit.com:80` instead of `-L 80:198.41.208.138:80`). 9 | 10 | Static linking breaks hostname resolution, but IMHO the pros overweight the cons. 11 | 12 | c-toxcore is the only direct dependency. c-toxcore requires libsodium and libevent_pthreads at the time of writing this, please refer to their install instructions for the current dependencies. Also pkg-config is required. 13 | 14 | ## Debian sid 15 | 16 | In Debian sid, toxcore is in the main repos so it's very easy to build a deb package. 17 | 18 | ``` 19 | apt install pkg-config build-essential make libtoxcore-dev dh-make git python3-jinja2 python3-requests 20 | git clone https://github.com/gjedeer/tuntox.git 21 | cd tuntox 22 | dh_make --createorig -s 23 | dpkg-buildpackage -us -uc 24 | ``` 25 | 26 | It's even easier to just build the binary: 27 | ``` 28 | apt install pkg-config build-essential make libtoxcore-dev git python3-jinja2 python3-requests 29 | git clone https://github.com/gjedeer/tuntox.git 30 | cd tuntox 31 | make 32 | ``` 33 | 34 | ## MacOS build 35 | Basically the same as above but: 36 | 37 | * static compiling is removed - you can't do this on MacOS platform (no, just don't) 38 | * because of removed `-static` you can't resolve hostnames (you can always put it into `hosts` file in your system) 39 | 40 | If you'd like to build on Mac do: `make -f Makefile.mac` 41 | 42 | # FreeBSD build 43 | ``` 44 | pkg install toxcore 45 | gcc -I/usr/local/include/ -L/usr/local/lib -o tuntox -lpthread -g -pthread -lm -static -lrt *.c /usr/local/lib/libtoxcore.a -lsodium 46 | ``` 47 | 48 | If someone knows why the hell pkg-config doesn't find toxcore or sodium on freebsd, please contact me or open a PR. 49 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:edge AS builder 2 | ARG TARGETPLATFORM 3 | ARG BUILDPLATFORM 4 | WORKDIR / 5 | RUN uname -a && echo http://dl-cdn.alpinelinux.org/alpine/edge/testing >> /etc/apk/repositories && apk add gcc g++ git make musl-dev cmake linux-headers libsodium-dev libsodium-static && git clone https://github.com/TokTok/c-toxcore.git /c-toxcore && cd /c-toxcore/ && git submodule update --init && cd /c-toxcore/build/ && cmake .. -DBUILD_TOXAV=OFF -DBOOTSTRAP_DAEMON=off -DBUILD_AV_TEST=off -DFULLY_STATIC=on && make && make install 6 | RUN git clone https://github.com/gjedeer/tuntox.git /tuntox && cd /tuntox && make tuntox 7 | 8 | FROM alpine:latest 9 | 10 | COPY scripts/tokssh /usr/bin/tokssh 11 | COPY --from=0 /tuntox/tuntox /usr/bin/tuntox 12 | 13 | RUN chmod +x /usr/bin/tuntox /usr/bin/tokssh && \ 14 | mkdir /data 15 | 16 | EXPOSE 33446/tcp 17 | EXPOSE 33446:33447/udp 18 | 19 | CMD ["/usr/bin/tuntox", "-C", "/data", "-t", "33446", "-u", "33446:33447", "-d"] 20 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | ## How to report crash issues? 2 | 3 | * [Learn to use GDB](https://wiki.ubuntu.com/Backtrace#Generation) (or see [Arch Wiki](https://wiki.archlinux.org/index.php/Debug_-_Getting_Traces#Getting_the_trace) if you can't stand seeing the Ubuntu logo) 4 | * Preferably, [build tuntox and c-toxcore from source](BUILD.md) 5 | * run tuntox with `-d -d -d` switch (yes, three times) on both sides (client and server) 6 | * Try reproducing the problem 7 | * Type `backtrace full` in gdb console when it crashes 8 | * Paste full debug output including gdb output in your issue. Don't forget to paste log from the other side (eg. from a client when you're reporting a server crash). 9 | * Describe exactly how you reproduced the problem. Preferably try reproducing it again. 10 | 11 | ## How to report non-crash issues? 12 | 13 | * Make sure you're running the latest version 14 | * run tuntox with `-d -d -d` switch (yes, three times): 15 | 16 | ``` 17 | tuntox -d -d -d -i ABDE4CF4541C27DBE36A812FF6752F71A9F44D1CF917CE489B30CC3D742500039B86C14F85F9 18 | ``` 19 | 20 | * Try reproducing the problem and note approximate date/time of the problem, so that logs can be cross-referenced 21 | * Depending on the nature of the problem, logs from both server and client may be needed 22 | * Describe exactly how you reproduced the problem. Preferably try reproducing it again. 23 | 24 | ## Why is my connection slow? 25 | 26 | The actual p2p connection is made by the [c-toxcore](https://github.com/TokTok/c-toxcore) library. The way it works is: it tries to establish a direct connection between peers and falls back to [TCP relays](https://nodes.tox.chat/) if that's impossible. 27 | 28 | The direct connection code doesn't see much work and c-toxcore sometimes uses a TCP relay even when both peers have a public IP address and can reach each other directly. 29 | 30 | Also please note that sometimes the connection improves after a few minutes as the peers discover each other. 31 | 32 | You're going to get the best connection if you see the following message on the client: 33 | 34 | ``` 35 | 2018-03-24 08:59:21: [INFO] Friend request accepted (An UDP connection has been established)! 36 | ``` 37 | 38 | The connection is likely to have worse latency when you see the following: 39 | 40 | ``` 41 | 2018-03-24 08:57:21: [INFO] Friend request accepted (A TCP connection has been established (via TCP relay))! 42 | ``` 43 | 44 | There's, however, a chance that it will upgrade to UDP after a few minutes: 45 | 46 | ``` 47 | 2018-03-24 10:17:06: [INFO] Friend connection status changed to: An UDP connection has been established 48 | ``` 49 | 50 | ## I have a direct UDP connection. Why isn't my connection faster? 51 | 52 | Wait until https://github.com/gjedeer/tuntox/issues/41 is implemented. This change should improve speed and latency in the 10 Mbit/s+ range. 53 | 54 | ## How do I run over proxy/Tor? 55 | 56 | tuntox honors the `ALL_PROXY` environment variable when connecting to the Tox network. HTTP and SOCKS5 proxies are supported. 57 | 58 | In server mode, it does not use the proxy for tunneled connections - just for tox protocol. If that's important for you that tunelled connections use a proxy, use proxychains, torify or a similar tool. In other words, if a client connects and requests google.com:443, the server will not use a proxy between itself and google.com. 59 | 60 | ``` 61 | ALL_PROXY=socks5://127.0.0.1:9050 ./tuntox 62 | ALL_PROXY=http://42.3.182.149:80 ./tuntox -i ABCD123 -p 63 | ``` 64 | 65 | ## Are there distribution packages? 66 | 67 | In repos: 68 | 69 | * [Arch](https://www.archlinux.org/packages/community/x86_64/tuntox/) 70 | * [Homebrew](https://formulae.brew.sh/formula/tuntox) 71 | * [NixOS](https://github.com/NixOS/nixpkgs/blob/nixos-22.05/pkgs/tools/networking/tuntox/default.nix#L73) `nix-env -iA nixos.tuntox` 72 | * [Pentoo](https://github.com/pentoo/pentoo-overlay/tree/master/net-vpn/tuntox) 73 | * [Void](https://github.com/void-linux/void-packages/tree/master/srcpkgs/tuntox) 74 | 75 | Work in progress: 76 | * [Debian](https://bitbucket.org/gjedeer/tuntox/downloads/) 77 | 78 | ## Can I restrict client access to certain hosts only? 79 | 80 | Create a whitelist file with contents like this: 81 | 82 | ``` 83 | 1.2.3.4:22 84 | 127.0.0.1:80 85 | *:6667 86 | 2.3.4.5:0 87 | ``` 88 | 89 | Asterisk is a wildcard for hosts. Zero is a wildcard for ports. 90 | 91 | Then run Tuntox with `-f `. 92 | 93 | ## Can I run it with Docker? 94 | 95 | ATTENTION - DOCKER IMAGE MOVED FROM GITLAB TO DOCKERHUB ON 2020-08-15 96 | 97 | I've made a [Docker image](https://hub.docker.com/r/gdr1/tuntox) by bundling a static build with Alpine Linux, it's built automatically by Dockerhub every time I push code to Github. There's a [Dockerfile](Dockerfile) and [docker-compose.yaml](scripts/docker-compose.yaml) if you want to build the image yourself. 98 | 99 | The tox config is stored in `/data` and that's where you want to attach your volumes. 100 | 101 | ``` 102 | docker run -e 'TUNTOX_SHARED_SECRET=myassfeelsweird' -v /tmp/tt:/data -it gdr1/tuntox:latest 103 | ``` 104 | 105 | The binary is in `/usr/bin/tuntox` (and `/usr/bin/tokssh`): 106 | ``` 107 | docker run -e 'TUNTOX_SHARED_SECRET=myassfeelsweird' -it gdr1/tuntox:latest /usr/bin/tuntox -i 1234abc -p 108 | ``` 109 | 110 | ## Can I run it on Windows? 111 | 112 | There's no native Windows version but, in the spirit of "just use Wine" answers, try the following: 113 | 114 | * Why don't you install [Docker for Windows](https://docs.docker.com/docker-for-windows/install/) and use the Docker image in Linux Containers mode? 115 | * [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10) works with tuntox binaries too (see Releases tab on Github). To use the smallest amount of disk space, use Alpine Linux instead of Ubuntu (but it works on both). [screenshot](screenshots/wsl.png) 116 | 117 | ## Is your website a joke? 118 | 119 | You're a joke for not using NoScript. Just disable JS if you don't like the scroller. 120 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SOURCES = $(wildcard *.c) 2 | DEPS=toxcore 3 | CC?=$(CC) 4 | CFLAGS=-g -Wall #-std=c99 5 | CFLAGS += $(shell pkg-config --cflags $(DEPS)) 6 | LDFLAGS=-g -pthread -lm -static 7 | LDFLAGS += $(shell pkg-config --static --libs $(DEPS)) 8 | DSO_LDFLAGS=-g -pthread -lm 9 | DSO_LDFLAGS += $(shell pkg-config --libs $(DEPS)) 10 | OBJECTS=$(SOURCES:.c=.o) 11 | INCLUDES = $(wildcard *.h) 12 | PYTHON = /usr/bin/env python3 13 | INSTALL = install -C 14 | INSTALL_MKDIR = $(INSTALL) -d -m 755 15 | OS=$(shell uname) 16 | 17 | ifneq ($(OS),Darwin) 18 | LDFLAGS += -lrt 19 | DSO_LDFLAGS += -lrt 20 | endif 21 | 22 | PREFIX ?= /usr 23 | BINDIR ?= $(PREFIX)/bin 24 | 25 | # Targets 26 | all: tuntox tuntox_nostatic 27 | 28 | gitversion.h: FORCE 29 | @if [ -d .git ]; then \ 30 | echo " GEN $@"; \ 31 | echo "#define GITVERSION \"$(shell git rev-parse HEAD)\"" > $@; \ 32 | fi 33 | 34 | termux: PREFIX=/data/data/com.termux/files/usr 35 | termux: CFLAGS += -I$(PREFIX)/include 36 | termux: TERMUX_LDFLAGS = -L$(PREFIX)/lib -ltoxcore -ltoxencryptsave -lsodium -lm 37 | termux: 38 | $(MAKE) clean 39 | $(MAKE) gitversion.h tox_bootstrap.h $(OBJECTS) 40 | $(CC) -o tuntox $(OBJECTS) $(TERMUX_LDFLAGS) 41 | 42 | 43 | FORCE: 44 | 45 | tox_bootstrap.h: 46 | $(PYTHON) generate_tox_bootstrap.py 47 | 48 | %.o: %.c $(INCLUDES) gitversion.h tox_bootstrap.h 49 | @echo " CC $@" 50 | @$(CC) -c $(CFLAGS) $< -o $@ 51 | 52 | tuntox: $(OBJECTS) $(INCLUDES) 53 | $(CC) -o $@ $(OBJECTS) -lpthread $(LDFLAGS) 54 | 55 | tuntox_nostatic: $(OBJECTS) $(INCLUDES) 56 | $(CC) -o $@ $(OBJECTS) -lpthread $(DSO_LDFLAGS) 57 | 58 | cscope.out: 59 | @echo " GEN $@" 60 | @cscope -bv ./*.[ch] &> /dev/null 61 | 62 | clean: 63 | $(RM) *.o tuntox cscope.out gitversion.h tox_bootstrap.h 64 | 65 | install: tuntox_nostatic 66 | $(INSTALL_MKDIR) -d $(DESTDIR)$(BINDIR) 67 | $(INSTALL) tuntox_nostatic $(DESTDIR)$(BINDIR)/tuntox 68 | 69 | .PHONY: all clean tuntox termux 70 | -------------------------------------------------------------------------------- /Makefile.mac: -------------------------------------------------------------------------------- 1 | SOURCES = $(wildcard *.c) 2 | DEPS=toxcore 3 | CC=gcc 4 | CFLAGS=-g #-std=c99 5 | CFLAGS += $(shell pkg-config --cflags $(DEPS)) 6 | LDFLAGS=-g -lm 7 | LDFLAGS += $(shell pkg-config --libs $(DEPS)) 8 | OBJECTS=$(SOURCES:.c=.o) 9 | INCLUDES = $(wildcard *.h) 10 | LIB_DIR ?= /usr/local/lib 11 | 12 | all: cscope.out tuntox 13 | 14 | gitversion.h: .git/HEAD .git/index 15 | echo "#define GITVERSION \"$(shell git rev-parse HEAD)\"" > $@ 16 | 17 | gitversion.c: gitversion.h 18 | 19 | .c.o: $(INCLUDES) 20 | $(CC) $(CFLAGS) $< -c -o $@ 21 | 22 | tuntox: $(OBJECTS) $(INCLUDES) 23 | $(CC) -o $@ $(OBJECTS) -ltoxcore $(LDFLAGS) $(LIB_DIR)/libsodium.a $(LIB_DIR)/libtoxcore.a 24 | 25 | cscope.out: 26 | cscope -bv ./*.[ch] 27 | 28 | clean: 29 | rm -rf *.o tuntox gitversion.h 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | Tuntox is a program which forwards TCP connections over the [Tox](https://tox.chat/) protocol. This allows low-latency access to distant machines behind a NAT you can't control or with a dynamic IP address. 4 | 5 | Tuntox is a single binary which may run in client mode or server mode. As a rule of thumb, run the server on the remote machine you want to access and the client on your local computer from which you want to access the server. 6 | 7 | **Tuntox is in early work in progress stage**. It won't kill your goats but it may segfault, leak memory or have security issues (although I tried to make it rather secure). 8 | 9 | If you don't know what Tox is - it's an instant messenger protocol which is fully P2P, supports audio/video calls and file transfers. Unlike Skype it's fully open and unlike, say, XMPP - the calls and file transfers actually work P2P. Check out https://tox.chat/ and download a client when you have a chance. 10 | 11 | [![Coverity Scan Build Status](https://scan.coverity.com/projects/5690/badge.svg)](https://scan.coverity.com/projects/5690) [![Travis Build Status](https://travis-ci.org/gjedeer/tuntox.svg?branch=master)](https://travis-ci.org/gjedeer/tuntox) 12 | 13 | ## Binary 14 | 15 | Get the binaries from Releases tab on github. Just download the correct file for your architecture, execute chmod +x and you're done. The binaries are signed with my PGP key, [11C1 B15A 5D5D D662 E469 928A EBDA 6B97 4ED3 D2B7](https://keys.openpgp.org/search?q=11C1B15A5D5DD662E469928AEBDA6B974ED3D2B7). 16 | 17 | If you miss the times when men wrote their own device drivers, see BUILD.md. 18 | 19 | ## Running the server 20 | 21 | Run the Tuntox server on a laptop which connects via 3G, on your home computer behind six NATs or on your Raspberry Pi. No ports need to be forwarded to its public IP - the machine will be accessible via the Tox overlay network. 22 | 23 | ./tuntox 24 | 25 | runs the server in the foreground. When the server starts, it will print its Tox ID to the output - note it, you will need it later to access the machine from outside. 26 | 27 | If you terminate the server (Ctrl-C) and start again, it will generate a new Tox ID and you'll need to write it down again. It kind of defeats the purpose, so you'll want to help the server store its Tox ID somewhere. By default it saves a file in /etc/tuntox/, so if you create this directory and chown it so that it's accessible to tuntox, it will have a fixed Tox ID. 28 | 29 | Alternatively you may use the -C switch instead: 30 | 31 | ./tuntox -C /path/to/the/config/directory/ 32 | 33 | To daemonize on startup, add -z: 34 | 35 | /path/to/tuntox -z 36 | 37 | Or, if you run something like supervisord or systemd, you're welcome to contribute a configuration file for the system of your choice (see #3, #4, #6). There's absolutely no need to run the server as root. 38 | 39 | ## Client 40 | 41 | So, the laptop now has the Tuntox server installed. How do you connect to it? 42 | 43 | ./tuntox -i -L 2222:127.0.0.1:22 44 | 45 | where `` is the ID you noted down when setting up the server. You didn't forget to write it down, did you? 46 | 47 | After you run this command, open a second terminal window and execute: 48 | 49 | ssh -p 2222 myuser@localhost 50 | 51 | Magic, port 2222 on your localhost is now the SSH server on the machine which runs the Tuntox server. 52 | 53 | The -L switch works (almost) the same way it does in SSH. For the uninitiated, -L A:B:C means "forward port C on ip B to port A on localhost". Unlike SSH, you can't use hostnames for B (unless you link the binary dynamically). 54 | 55 | Alternatively, SSH ProxyCommand mode works too: 56 | 57 | ssh -o ProxyCommand='./tuntox -i -W localhost:22' gdr@localhost 58 | 59 | Fun stuff: [VPN over Tox](VPN.md) 60 | 61 | Client can be ran as a regular non-root user, [unless A < 1024](https://www.linuxquestions.org/linux/articles/Technical/Why_can_only_root_listen_to_ports_below_1024) ("A" is the local port). There's a [workaround](http://unix.stackexchange.com/a/10737) available. 62 | 63 | ## Security / threat model 64 | 65 | **TUNTOX IS NOT SECURE WITHOUT THE -s SWITCH.** Supply *-s yourpassword* both on the server and the client, and you will be fine. This switch is introduced in 0.0.4, codename "Mr. Lahey's Got My Porno Tape!". Even better, run `TUNTOX_SHARED_SECRET=yourpassword tuntox ...` on both sides. 66 | 67 | The Tuntox server generates a new Tox ID on every startup, or saves its private key in a file. Anyone who wants to connect to this server needs its Tox ID, which consists of the publicly-known pubkey and a secret 32-bit "antispam" value. Then, the client sends a shared secret which is then compared to the secred supplied on server's command line. If they don't match, friend request is left unanswered. 68 | 69 | Therefore, posession of the server's Tox ID and a secret should be considered equivalent to posession of an Unix account with SSH access. Tuntox does not implement remote shell capability, but it is possible that it's exploitable. 70 | 71 | PSK authentication is optional but recommended - it's only enabled when -s switch is present on server side or the TUNTOX_SHARED_SECRET environment variable is set. PSK is sent as Tox friend request message - as far as the author understands libtoxcore code, it's encrypted using server's public EC key. 72 | 73 | The Tuntox Server can optionally allow only whitelisted ToxIDs. Supply *-i yourallowedtoxid* one time or more to add a ToxID to the whitelist. Note: The default client behavior is to generate a new ToxID for every run (because author thinks it's a nice privacy feature). You will want to use the -C switch in client to force reading a saved identity from tox_save. 74 | 75 | Tuntox is piggybacking on the Tox protocol, which itself has not been audited by security researchers. Tox crypto has been implemented with libsodium (which is based on Bernstein's NaCl) and thus uses the ecliptic curve 25519 for key exchange and salsa20 for stream encryption. According to the author's best knowledge, libsodium makes it as hard as possible to get crypto wrong, but we don't know until Tox has been audited. 76 | 77 | ## FAQ 78 | 79 | [yes, there is one](FAQ.md) 80 | 81 | ## License 82 | 83 | Sorry about GPLv3 - both toxcore and utox (from which I borrowed some code) are GPLv3. 84 | 85 | Thank you to the toxcore and utox developers without whom this program would never exist. 86 | 87 | Thank you Mr_4551 for your help and motivation. 88 | -------------------------------------------------------------------------------- /VPN.md: -------------------------------------------------------------------------------- 1 | ## How to make a point-to-point VPN 2 | 3 | Socat is a powerful tool which can work together with Tuntox. 4 | 5 | On the server (where tuntox is already running): 6 | 7 | socat -d -d 'TCP-LISTEN:9876' 'TUN:10.20.30.41/24,up' 8 | 9 | On the client: 10 | 11 | socat -d -d TUN:10.20.30.40/24,up 'SYSTEM:./tuntox -W 127.0.0.1@9876 -i 86e70ffe9f835b12667d296f2df9c307ba1aff06' 12 | 13 | Viola, you have a point-to-point VPN. On client: 14 | 15 | # ping 10.20.30.41 16 | PING 10.20.30.41 (10.20.30.41) 56(84) bytes of data. 17 | 64 bytes from 10.20.30.41: icmp_seq=1 ttl=64 time=138 ms 18 | 64 bytes from 10.20.30.41: icmp_seq=2 ttl=64 time=169 ms 19 | 64 bytes from 10.20.30.41: icmp_seq=3 ttl=64 time=130 ms 20 | 64 bytes from 10.20.30.41: icmp_seq=4 ttl=64 time=90.8 ms 21 | 64 bytes from 10.20.30.41: icmp_seq=5 ttl=64 time=50.7 ms 22 | 23 | ## Full madness mode: tunnelling VPN over SSH over Tox 24 | 25 | No need to log in run and run socat on the server. 26 | 27 | Also: inefficient, insecure (requires PermitRootLogin yes on server). 28 | 29 | On the client: 30 | 31 | socat -d -d TUN:10.20.30.40/24,up 'SYSTEM:ssh root@localhost -o ProxyCommand=\"./tuntox -W "127.0.0.1:22" -d -i 86e70ffe9f835b12667d296f2df9c307ba1aff06\" socat -d -d - "TUN:10.20.30.41/24,up"' 32 | 33 | # ping 10.20.30.41 34 | PING 10.20.30.41 (10.20.30.41) 56(84) bytes of data. 35 | 64 bytes from 10.20.30.41: icmp_seq=1 ttl=64 time=50.6 ms 36 | 64 bytes from 10.20.30.41: icmp_seq=2 ttl=64 time=81.2 ms 37 | 64 bytes from 10.20.30.41: icmp_seq=3 ttl=64 time=50.3 ms 38 | 64 bytes from 10.20.30.41: icmp_seq=4 ttl=64 time=151 ms 39 | 64 bytes from 10.20.30.41: icmp_seq=5 ttl=64 time=50.3 ms 40 | 41 | Based on [Ben Martin's article](https://web.archive.org/web/20160102211752/http://www.linux.com/news/software/developer/17942-socat-the-general-bidirectional-pipe-handler) 42 | 43 | I've also heard about a new program called [ToxVPN](https://github.com/cleverca22/toxvpn), who knows - maybe it does a better job? And more recently someone created [toxtun](http://toxtun.jschwab.org/), slowclap.gif for the creative choice of name. 44 | -------------------------------------------------------------------------------- /bitbucket-pipelines.yml: -------------------------------------------------------------------------------- 1 | image: debian:sid 2 | pipelines: 3 | default: 4 | - step: 5 | name: Build deb 6 | image: debian:sid 7 | caches: 8 | - apt 9 | script: 10 | - apt update 11 | - apt -y install pkg-config build-essential make libtoxcore-dev dh-make python3-jinja2 python3-requests curl git 12 | #- dh_make -y --createorig -s -p `cat bb_version.txt` || echo 13 | - tar -zcf ../tuntox_0.0.10.1.orig.tar.gz . 14 | - dpkg-buildpackage -us -uc 15 | - ls -l .. 16 | - echo tuntox_0.0.10.1.`date +%Y%m%d%H%M%S`-$BITBUCKET_COMMIT >../bb_version.txt 17 | - cp ../tuntox_0.0.10.1-1_amd64.deb ../`cat ../bb_version.txt`_amd64.deb 18 | - curl -X POST "https://${BITBUCKET_USERNAME}:${BITBUCKET_APP_PASSWORD}@api.bitbucket.org/2.0/repositories/${BITBUCKET_REPO_OWNER}/${BITBUCKET_REPO_SLUG}/downloads" --form files=@"../"`cat ../bb_version.txt`"_amd64.deb" 19 | 20 | 21 | 22 | 23 | definitions: 24 | caches: 25 | apt: /var/cache/apt 26 | 27 | -------------------------------------------------------------------------------- /cJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef cJSON__h 24 | #define cJSON__h 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | 31 | #if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) 32 | #define __WINDOWS__ 33 | #endif 34 | 35 | #ifdef __WINDOWS__ 36 | 37 | /* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: 38 | 39 | CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols 40 | CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) 41 | CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol 42 | 43 | For *nix builds that support visibility attribute, you can define similar behavior by 44 | 45 | setting default visibility to hidden by adding 46 | -fvisibility=hidden (for gcc) 47 | or 48 | -xldscope=hidden (for sun cc) 49 | to CFLAGS 50 | 51 | then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does 52 | 53 | */ 54 | 55 | #define CJSON_CDECL __cdecl 56 | #define CJSON_STDCALL __stdcall 57 | 58 | /* export symbols by default, this is necessary for copy pasting the C and header file */ 59 | #if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) 60 | #define CJSON_EXPORT_SYMBOLS 61 | #endif 62 | 63 | #if defined(CJSON_HIDE_SYMBOLS) 64 | #define CJSON_PUBLIC(type) type CJSON_STDCALL 65 | #elif defined(CJSON_EXPORT_SYMBOLS) 66 | #define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL 67 | #elif defined(CJSON_IMPORT_SYMBOLS) 68 | #define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL 69 | #endif 70 | #else /* !__WINDOWS__ */ 71 | #define CJSON_CDECL 72 | #define CJSON_STDCALL 73 | 74 | #if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) 75 | #define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type 76 | #else 77 | #define CJSON_PUBLIC(type) type 78 | #endif 79 | #endif 80 | 81 | /* project version */ 82 | #define CJSON_VERSION_MAJOR 1 83 | #define CJSON_VERSION_MINOR 7 84 | #define CJSON_VERSION_PATCH 15 85 | 86 | #include 87 | 88 | /* cJSON Types: */ 89 | #define cJSON_Invalid (0) 90 | #define cJSON_False (1 << 0) 91 | #define cJSON_True (1 << 1) 92 | #define cJSON_NULL (1 << 2) 93 | #define cJSON_Number (1 << 3) 94 | #define cJSON_String (1 << 4) 95 | #define cJSON_Array (1 << 5) 96 | #define cJSON_Object (1 << 6) 97 | #define cJSON_Raw (1 << 7) /* raw json */ 98 | 99 | #define cJSON_IsReference 256 100 | #define cJSON_StringIsConst 512 101 | 102 | /* The cJSON structure: */ 103 | typedef struct cJSON 104 | { 105 | /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ 106 | struct cJSON *next; 107 | struct cJSON *prev; 108 | /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ 109 | struct cJSON *child; 110 | 111 | /* The type of the item, as above. */ 112 | int type; 113 | 114 | /* The item's string, if type==cJSON_String and type == cJSON_Raw */ 115 | char *valuestring; 116 | /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ 117 | int valueint; 118 | /* The item's number, if type==cJSON_Number */ 119 | double valuedouble; 120 | 121 | /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ 122 | char *string; 123 | } cJSON; 124 | 125 | typedef struct cJSON_Hooks 126 | { 127 | /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ 128 | void *(CJSON_CDECL *malloc_fn)(size_t sz); 129 | void (CJSON_CDECL *free_fn)(void *ptr); 130 | } cJSON_Hooks; 131 | 132 | typedef int cJSON_bool; 133 | 134 | /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. 135 | * This is to prevent stack overflows. */ 136 | #ifndef CJSON_NESTING_LIMIT 137 | #define CJSON_NESTING_LIMIT 1000 138 | #endif 139 | 140 | /* returns the version of cJSON as a string */ 141 | CJSON_PUBLIC(const char*) cJSON_Version(void); 142 | 143 | /* Supply malloc, realloc and free functions to cJSON */ 144 | CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); 145 | 146 | /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ 147 | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ 148 | CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); 149 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); 150 | /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ 151 | /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ 152 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); 153 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); 154 | 155 | /* Render a cJSON entity to text for transfer/storage. */ 156 | CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); 157 | /* Render a cJSON entity to text for transfer/storage without any formatting. */ 158 | CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); 159 | /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ 160 | CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); 161 | /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ 162 | /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ 163 | CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); 164 | /* Delete a cJSON entity and all subentities. */ 165 | CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); 166 | 167 | /* Returns the number of items in an array (or object). */ 168 | CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); 169 | /* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ 170 | CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); 171 | /* Get item "string" from object. Case insensitive. */ 172 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); 173 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); 174 | CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); 175 | /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ 176 | CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); 177 | 178 | /* Check item type and return its value */ 179 | CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); 180 | CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); 181 | 182 | /* These functions check the type of an item */ 183 | CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); 184 | CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); 185 | CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); 186 | CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); 187 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); 188 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); 189 | CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); 190 | CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); 191 | CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); 192 | CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); 193 | 194 | /* These calls create a cJSON item of the appropriate type. */ 195 | CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); 196 | CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); 197 | CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); 198 | CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); 199 | CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); 200 | CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); 201 | /* raw json */ 202 | CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); 203 | CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); 204 | CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); 205 | 206 | /* Create a string where valuestring references a string so 207 | * it will not be freed by cJSON_Delete */ 208 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); 209 | /* Create an object/array that only references it's elements so 210 | * they will not be freed by cJSON_Delete */ 211 | CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); 212 | CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); 213 | 214 | /* These utilities create an Array of count items. 215 | * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ 216 | CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); 217 | CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); 218 | CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); 219 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); 220 | 221 | /* Append item to the specified array/object. */ 222 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); 223 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); 224 | /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. 225 | * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before 226 | * writing to `item->string` */ 227 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); 228 | /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ 229 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 230 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); 231 | 232 | /* Remove/Detach items from Arrays/Objects. */ 233 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); 234 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); 235 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); 236 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); 237 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); 238 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); 239 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); 240 | 241 | /* Update array items. */ 242 | CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ 243 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); 244 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); 245 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); 246 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); 247 | 248 | /* Duplicate a cJSON item */ 249 | CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); 250 | /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will 251 | * need to be released. With recurse!=0, it will duplicate any children connected to the item. 252 | * The item->next and ->prev pointers are always zero on return from Duplicate. */ 253 | /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. 254 | * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ 255 | CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); 256 | 257 | /* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. 258 | * The input pointer json cannot point to a read-only address area, such as a string constant, 259 | * but should point to a readable and writable address area. */ 260 | CJSON_PUBLIC(void) cJSON_Minify(char *json); 261 | 262 | /* Helper functions for creating and adding items to an object at the same time. 263 | * They return the added item or NULL on failure. */ 264 | CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); 265 | CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); 266 | CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); 267 | CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); 268 | CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); 269 | CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); 270 | CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); 271 | CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); 272 | CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); 273 | 274 | /* When assigning an integer value, it needs to be propagated to valuedouble too. */ 275 | #define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) 276 | /* helper for the cJSON_SetNumberValue macro */ 277 | CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); 278 | #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) 279 | /* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ 280 | CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); 281 | 282 | /* Macro for iterating over an array or object */ 283 | #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) 284 | 285 | /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ 286 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size); 287 | CJSON_PUBLIC(void) cJSON_free(void *object); 288 | 289 | #ifdef __cplusplus 290 | } 291 | #endif 292 | 293 | #endif 294 | -------------------------------------------------------------------------------- /client.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* MacOS related */ 4 | #ifdef __MACH__ 5 | #include "mach.h" 6 | #endif 7 | 8 | #include "log.h" 9 | #include "main.h" 10 | #include "client.h" 11 | 12 | /* The state machine */ 13 | int state = CLIENT_STATE_INITIAL; 14 | 15 | /* Used in ping mode */ 16 | struct timespec ping_sent_time; 17 | 18 | fd_set client_master_fdset; 19 | int client_select_nfds; 20 | 21 | int handle_pong_frame() 22 | { 23 | struct timespec pong_rcvd_time; 24 | double secs1, secs2; 25 | 26 | clock_gettime(CLOCK_MONOTONIC, &pong_rcvd_time); 27 | 28 | secs1 = (1.0 * ping_sent_time.tv_sec) + (1e-9 * ping_sent_time.tv_nsec); 29 | secs2 = (1.0 * pong_rcvd_time.tv_sec) + (1e-9 * pong_rcvd_time.tv_nsec); 30 | 31 | log_printf(L_INFO, "GOT PONG! Time = %.3fs\n", secs2-secs1); 32 | 33 | if(ping_mode) 34 | { 35 | state = CLIENT_STATE_SEND_PING; 36 | } 37 | return 0; 38 | } 39 | 40 | int local_bind_one(local_port_forward *port_forward) 41 | { 42 | struct addrinfo hints, *res; 43 | char port[6]; 44 | int yes = 1; 45 | int flags; 46 | int gai_status; 47 | int setsockopt_status; 48 | 49 | snprintf(port, 6, "%d", port_forward->local_port); 50 | 51 | memset(&hints, 0, sizeof hints); 52 | hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever 53 | hints.ai_socktype = SOCK_STREAM; 54 | hints.ai_flags = AI_PASSIVE; // fill in my IP for me 55 | 56 | gai_status = getaddrinfo(NULL, port, &hints, &res); 57 | if(gai_status != 0) 58 | { 59 | log_printf(L_ERROR, "getaddrinfo: %s\n", gai_strerror(gai_status)); 60 | exit(1); 61 | } 62 | 63 | port_forward->bind_sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 64 | if(port_forward->bind_sockfd < 0) 65 | { 66 | log_printf(L_ERROR, "Could not create a socket for local listening: %s\n", strerror(errno)); 67 | freeaddrinfo(res); 68 | exit(1); 69 | } 70 | 71 | setsockopt_status = setsockopt(port_forward->bind_sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); 72 | if(setsockopt_status < 0) 73 | { 74 | log_printf(L_ERROR, "Could not set socket options: %s\n", 75 | strerror(errno)); 76 | freeaddrinfo(res); 77 | exit(1); 78 | } 79 | 80 | /* Set O_NONBLOCK to make accept() non-blocking */ 81 | if (-1 == (flags = fcntl(port_forward->bind_sockfd, F_GETFL, 0))) 82 | { 83 | flags = 0; 84 | } 85 | if(fcntl(port_forward->bind_sockfd, F_SETFL, flags | O_NONBLOCK) < 0) 86 | { 87 | log_printf(L_ERROR, "Could not make the socket non-blocking: %s\n", strerror(errno)); 88 | freeaddrinfo(res); 89 | exit(1); 90 | } 91 | 92 | if(bind(port_forward->bind_sockfd, res->ai_addr, res->ai_addrlen) < 0) 93 | { 94 | log_printf(L_ERROR, "Bind to port %d failed: %s\n", port_forward->local_port, strerror(errno)); 95 | freeaddrinfo(res); 96 | close(port_forward->bind_sockfd); 97 | exit(1); 98 | } 99 | 100 | freeaddrinfo(res); 101 | 102 | if(listen(port_forward->bind_sockfd, 1) < 0) 103 | { 104 | log_printf(L_ERROR, "Listening on port %d failed: %s\n", port_forward->local_port, strerror(errno)); 105 | close(port_forward->bind_sockfd); 106 | exit(1); 107 | } 108 | 109 | log_printf(L_DEBUG, "Bound to local port %d sockfd %d\n", port_forward->local_port, port_forward->bind_sockfd); 110 | 111 | return 0; 112 | } 113 | 114 | void local_bind() { 115 | local_port_forward *port_forward; 116 | 117 | LL_FOREACH(local_port_forwards, port_forward) 118 | { 119 | local_bind_one(port_forward); 120 | } 121 | } 122 | 123 | /* Bind the client.sockfd to a tunnel */ 124 | int handle_acktunnel_frame(protocol_frame *rcvd_frame) 125 | { 126 | uint32_t local_forward_id; 127 | local_port_forward *forward; 128 | tunnel *tun; 129 | 130 | if(!client_mode) 131 | { 132 | log_printf(L_WARNING, "Got ACK tunnel frame when not in client mode!?\n"); 133 | return -1; 134 | } 135 | 136 | if(rcvd_frame->data_length < 3) 137 | { 138 | log_printf(L_WARNING, "Got ACK tunnel frame with not enough data"); 139 | return -1; 140 | } 141 | 142 | if(rcvd_frame->data_length > PROTOCOL_MAX_PACKET_SIZE) { 143 | log_printf(L_WARNING, "Got ACK tunnel with wrong data length"); 144 | return -1; 145 | } 146 | 147 | local_forward_id = INT32_AT((rcvd_frame->data), 0); 148 | 149 | log_printf(L_DEBUG2, "Got ACK tunnel frame for local forward %ld", local_forward_id); 150 | 151 | forward = find_pending_forward_by_id(local_forward_id); 152 | if(!forward) 153 | { 154 | log_printf(L_WARNING, "Got ACK tunnel with wrong forward ID %ld", local_forward_id); 155 | return -1; 156 | } 157 | 158 | tun = tunnel_create( 159 | forward->accept_sockfd, /* sockfd */ 160 | rcvd_frame->connid, 161 | rcvd_frame->friendnumber 162 | ); 163 | 164 | /* Mark that we can accept() another connection */ 165 | forward->accept_sockfd = -1; 166 | 167 | if(client_local_port_mode || client_pipe_mode) 168 | { 169 | FD_SET(tun->sockfd, &client_master_fdset); 170 | update_select_nfds(tun->sockfd, &client_master_fdset, &client_select_nfds); 171 | if(client_local_port_mode) 172 | { 173 | log_printf(L_INFO, "Accepted a new connection on port %d sockfd %d connid %d\n", forward->local_port, tun->sockfd, tun->connid); 174 | } 175 | } 176 | else 177 | { 178 | log_printf(L_ERROR, "This tunnel mode is not supported yet\n"); 179 | exit(1); 180 | } 181 | 182 | return 0; 183 | } 184 | 185 | /* Handle a TCP frame received from server */ 186 | int handle_server_tcp_frame(protocol_frame *rcvd_frame) 187 | { 188 | int offset = 0; 189 | tunnel *tun = NULL; 190 | int tun_id = rcvd_frame->connid; 191 | 192 | HASH_FIND_INT(by_id, &tun_id, tun); 193 | 194 | if(!tun) 195 | { 196 | log_printf(L_WARNING, "Got TCP frame with unknown tunnel ID %d\n", rcvd_frame->connid); 197 | return -1; 198 | } 199 | 200 | while(offset < rcvd_frame->data_length) 201 | { 202 | int sent_bytes; 203 | 204 | if(client_pipe_mode) 205 | { 206 | sent_bytes = write( 207 | 1, /* STDOUT */ 208 | rcvd_frame->data + offset, 209 | rcvd_frame->data_length - offset 210 | ); 211 | } 212 | else 213 | { 214 | sent_bytes = send( 215 | tun->sockfd, 216 | rcvd_frame->data + offset, 217 | rcvd_frame->data_length - offset, 218 | MSG_NOSIGNAL 219 | ); 220 | } 221 | 222 | 223 | if(sent_bytes < 0) 224 | { 225 | uint8_t data[PROTOCOL_BUFFER_OFFSET]; 226 | protocol_frame frame_st, *frame; 227 | 228 | log_printf(L_INFO, "Could not write to socket: %s\n", strerror(errno)); 229 | 230 | frame = &frame_st; 231 | memset(frame, 0, sizeof(protocol_frame)); 232 | frame->friendnumber = tun->friendnumber; 233 | frame->packet_type = PACKET_TYPE_TCP_FIN; 234 | frame->connid = tun->connid; 235 | frame->data_length = 0; 236 | send_frame(frame, data); 237 | if(tun->sockfd) 238 | { 239 | FD_CLR(tun->sockfd, &client_master_fdset); 240 | } 241 | tunnel_delete(tun); 242 | 243 | return -1; 244 | } 245 | 246 | offset += sent_bytes; 247 | } 248 | 249 | // printf("Got %d bytes from server - wrote to fd %d\n", rcvd_frame->data_length, tun->sockfd); 250 | 251 | return 0; 252 | } 253 | 254 | /* Delete tunnel and clear client-side fdset */ 255 | void client_close_tunnel(tunnel *tun) 256 | { 257 | if(tun->sockfd) 258 | { 259 | FD_CLR(tun->sockfd, &client_master_fdset); 260 | } 261 | 262 | tunnel_delete(tun); 263 | } 264 | 265 | /* Handle close-tunnel frame recived from the server */ 266 | int handle_server_tcp_fin_frame(protocol_frame *rcvd_frame) 267 | { 268 | tunnel *tun=NULL; 269 | int connid = rcvd_frame->connid; 270 | 271 | HASH_FIND_INT(by_id, &connid, tun); 272 | 273 | if(!tun) 274 | { 275 | log_printf(L_WARNING, "Got TCP FIN frame with unknown tunnel ID %d\n", rcvd_frame->connid); 276 | return -1; 277 | } 278 | 279 | if(tun->friendnumber != rcvd_frame->friendnumber) 280 | { 281 | log_printf(L_WARNING, "Friend #%d tried to close tunnel while server is #%d\n", rcvd_frame->friendnumber, tun->friendnumber); 282 | return -1; 283 | } 284 | 285 | client_close_tunnel(tun); 286 | 287 | return 0; 288 | } 289 | 290 | /* Close and delete all tunnels (when server went offline) */ 291 | void client_close_all_connections() 292 | { 293 | tunnel *tmp = NULL; 294 | tunnel *tun = NULL; 295 | 296 | HASH_ITER(hh, by_id, tun, tmp) 297 | { 298 | client_close_tunnel(tun); 299 | } 300 | } 301 | 302 | void on_friend_connection_status_changed(Tox *tox, uint32_t friend_number, Tox_Connection connection_status, 303 | void *user_data) 304 | { 305 | const char* status = readable_connection_status(connection_status); 306 | log_printf(L_INFO, "Friend connection status changed to: %s (%d)\n", status, connection_status); 307 | 308 | if(connection_status == TOX_CONNECTION_NONE) 309 | { 310 | state = CLIENT_STATE_CONNECTION_LOST; 311 | } 312 | } 313 | 314 | 315 | /* Main loop for the client */ 316 | int do_client_loop(uint8_t *tox_id_str) 317 | { 318 | unsigned char tox_packet_buf[PROTOCOL_MAX_PACKET_SIZE]; 319 | unsigned char tox_id[TOX_ADDRESS_SIZE]; 320 | uint32_t friendnumber = 0; 321 | struct timeval tv; 322 | fd_set fds; 323 | static time_t invitation_sent_time = 0; 324 | uint32_t invitations_sent = 0; 325 | TOX_ERR_FRIEND_QUERY friend_query_error; 326 | TOX_ERR_FRIEND_CUSTOM_PACKET custom_packet_error; 327 | local_port_forward *port_forward; 328 | 329 | FD_ZERO(&client_master_fdset); 330 | 331 | tox_callback_friend_lossless_packet(tox, parse_lossless_packet); 332 | tox_callback_friend_connection_status(tox, on_friend_connection_status_changed); 333 | 334 | if(!string_to_id(tox_id, tox_id_str)) 335 | { 336 | log_printf(L_ERROR, "Invalid Tox ID"); 337 | exit(1); 338 | } 339 | 340 | if(!ping_mode && !client_pipe_mode) 341 | { 342 | local_bind(); 343 | signal(SIGPIPE, SIG_IGN); 344 | } 345 | 346 | log_printf(L_INFO, "Connecting to Tox...\n"); 347 | 348 | while(1) 349 | { 350 | /* Let tox do its stuff */ 351 | tox_iterate(tox, NULL); 352 | 353 | switch(state) 354 | { 355 | /* 356 | * Send friend request 357 | */ 358 | case CLIENT_STATE_INITIAL: 359 | if(connection_status != TOX_CONNECTION_NONE) 360 | { 361 | state = CLIENT_STATE_CONNECTED; 362 | log_printf(L_DEBUG2, "Entered CLIENT_STATE_CONNECTED"); 363 | } 364 | break; 365 | case CLIENT_STATE_CONNECTED: 366 | { 367 | uint8_t* data = (uint8_t *)"Hi, fellow tuntox instance!"; 368 | uint16_t length = sizeof(data); 369 | /* https://github.com/TokTok/c-toxcore/blob/acb6b2d8543c8f2ea0c2e60dc046767cf5cc0de8/toxcore/tox.h#L1168 */ 370 | TOX_ERR_FRIEND_ADD add_error; 371 | 372 | if(use_shared_secret) 373 | { 374 | data = (uint8_t *)shared_secret; 375 | data[TOX_MAX_FRIEND_REQUEST_LENGTH-1] = '\0'; 376 | length = strlen((char *)data)+1; 377 | log_printf(L_DEBUG, "Sent shared secret of length %u\n", length); 378 | } 379 | 380 | if(invitations_sent == 0) 381 | { 382 | log_printf(L_INFO, "Connected. Sending friend request.\n"); 383 | } 384 | else 385 | { 386 | log_printf(L_INFO, "Sending another friend request.\n"); 387 | } 388 | 389 | friendnumber = tox_friend_add( 390 | tox, 391 | tox_id, 392 | data, 393 | length, 394 | &add_error 395 | ); 396 | 397 | if(add_error != TOX_ERR_FRIEND_ADD_OK) 398 | { 399 | unsigned char tox_printable_id[TOX_ADDRESS_SIZE * 2 + 1]; 400 | id_to_string(tox_printable_id, tox_id); 401 | log_printf(L_ERROR, "Error %u adding friend %s\n", add_error, tox_printable_id); 402 | exit(-1); 403 | } 404 | 405 | invitation_sent_time = time(NULL); 406 | invitations_sent++; 407 | state = CLIENT_STATE_SENTREQUEST; 408 | log_printf(L_DEBUG2, "Entered CLIENT_STATE_SENTREQUEST"); 409 | log_printf(L_INFO, "Waiting for friend to accept us...\n"); 410 | } 411 | break; 412 | case CLIENT_STATE_SENTREQUEST: 413 | { 414 | TOX_CONNECTION friend_connection_status; 415 | friend_connection_status = tox_friend_get_connection_status(tox, friendnumber, &friend_query_error); 416 | if(friend_query_error != TOX_ERR_FRIEND_QUERY_OK) 417 | { 418 | log_printf(L_DEBUG, "tox_friend_get_connection_status: error %u", friend_query_error); 419 | } 420 | else 421 | { 422 | if(friend_connection_status != TOX_CONNECTION_NONE) 423 | { 424 | const char* status = readable_connection_status(friend_connection_status); 425 | log_printf(L_INFO, "Friend request accepted (%s)!\n", status); 426 | state = CLIENT_STATE_REQUEST_ACCEPTED; 427 | log_printf(L_DEBUG2, "Entered CLIENT_STATE_REQUEST_ACCEPTED"); 428 | } 429 | else 430 | { 431 | if(1 && (time(NULL) - invitation_sent_time > 45)) 432 | { 433 | TOX_ERR_FRIEND_DELETE error = 0; 434 | 435 | log_printf(L_INFO, "Sending another friend request..."); 436 | tox_friend_delete( 437 | tox, 438 | friendnumber, 439 | &error); 440 | if(error != TOX_ERR_FRIEND_DELETE_OK) 441 | { 442 | log_printf(L_ERROR, "Error %u deleting friend before reconnection\n", error); 443 | exit(-1); 444 | } 445 | 446 | state = CLIENT_STATE_CONNECTED; 447 | log_printf(L_DEBUG2, "Entered CLIENT_STATE_CONNECTED"); 448 | } 449 | } 450 | } 451 | break; 452 | } 453 | case CLIENT_STATE_REQUEST_ACCEPTED: 454 | if(ping_mode) 455 | { 456 | state = CLIENT_STATE_SEND_PING; 457 | log_printf(L_DEBUG2, "Entered CLIENT_STATE_SEND_PING"); 458 | } 459 | else if(client_pipe_mode) 460 | { 461 | state = CLIENT_STATE_SETUP_PIPE; 462 | log_printf(L_DEBUG2, "Entered CLIENT_STATE_SETUP_PIPE"); 463 | } 464 | else 465 | { 466 | state = CLIENT_STATE_BIND_PORT; 467 | log_printf(L_DEBUG2, "Entered CLIENT_STATE_BIND_PORT"); 468 | } 469 | break; 470 | case CLIENT_STATE_SEND_PING: 471 | /* Send the ping packet */ 472 | { 473 | uint8_t data[] = { 474 | 0xa2, 0x6b, 0x01, 0x08, 0x00, 0x00, 0x00, 0x05, 475 | 0x48, 0x65, 0x6c, 0x6c, 0x6f 476 | }; 477 | 478 | clock_gettime(CLOCK_MONOTONIC, &ping_sent_time); 479 | tox_friend_send_lossless_packet( 480 | tox, 481 | friendnumber, 482 | data, 483 | sizeof(data), 484 | &custom_packet_error 485 | ); 486 | } 487 | if(custom_packet_error == TOX_ERR_FRIEND_CUSTOM_PACKET_OK) 488 | { 489 | state = CLIENT_STATE_PING_SENT; 490 | log_printf(L_DEBUG2, "Entered CLIENT_STATE_PING_SENT"); 491 | } 492 | else 493 | { 494 | log_printf(L_WARNING, "When sending ping packet: %u", custom_packet_error); 495 | } 496 | break; 497 | case CLIENT_STATE_PING_SENT: 498 | /* Just sit there and wait for pong */ 499 | break; 500 | 501 | case CLIENT_STATE_BIND_PORT: 502 | LL_FOREACH(local_port_forwards, port_forward) 503 | { 504 | log_printf(L_DEBUG2, "Processing local port %d", port_forward->local_port); 505 | if(port_forward->bind_sockfd < 0) 506 | { 507 | log_printf(L_ERROR, "Shutting down - could not bind to listening port %d\n", port_forward->local_port); 508 | state = CLIENT_STATE_SHUTDOWN; 509 | log_printf(L_DEBUG2, "Entered CLIENT_STATE_SHUTDOWN"); 510 | break; 511 | } 512 | else 513 | { 514 | state = CLIENT_STATE_FORWARDING; 515 | log_printf(L_DEBUG2, "Entered CLIENT_STATE_FORWARDING"); 516 | } 517 | } 518 | break; 519 | case CLIENT_STATE_SETUP_PIPE: 520 | LL_FOREACH(local_port_forwards, port_forward) 521 | { 522 | send_tunnel_request_packet( 523 | port_forward->remote_host, 524 | port_forward->remote_port, 525 | port_forward->forward_id, 526 | friendnumber 527 | ); 528 | } 529 | state = CLIENT_STATE_FORWARDING; 530 | log_printf(L_DEBUG2, "Entered CLIENT_STATE_FORWARDING"); 531 | break; 532 | case CLIENT_STATE_REQUEST_TUNNEL: 533 | LL_FOREACH(local_port_forwards, port_forward) 534 | { 535 | send_tunnel_request_packet( 536 | port_forward->remote_host, 537 | port_forward->remote_port, 538 | port_forward->forward_id, 539 | friendnumber 540 | ); 541 | } 542 | state = CLIENT_STATE_WAIT_FOR_ACKTUNNEL; 543 | break; 544 | case CLIENT_STATE_WAIT_FOR_ACKTUNNEL: 545 | LL_FOREACH(local_port_forwards, port_forward) 546 | { 547 | port_forward->accept_sockfd = 0; 548 | send_tunnel_request_packet( 549 | port_forward->remote_host, 550 | port_forward->remote_port, 551 | port_forward->forward_id, 552 | friendnumber 553 | ); 554 | } 555 | break; 556 | case CLIENT_STATE_FORWARDING: 557 | { 558 | int accept_fd = 0; 559 | int select_rv = 0; 560 | tunnel *tmp = NULL; 561 | tunnel *tun = NULL; 562 | local_port_forward *port_forward; 563 | 564 | tv.tv_sec = 0; 565 | tv.tv_usec = 20000; 566 | fds = client_master_fdset; 567 | 568 | /* Handle accepting new connections */ 569 | LL_FOREACH(local_port_forwards, port_forward) 570 | { 571 | if(!client_pipe_mode && 572 | port_forward->accept_sockfd <= 0) /* Don't accept if we're already waiting to establish a tunnel */ 573 | { 574 | //log_printf(L_DEBUG2, "FORWARDING: checking fd %d for local port %d", port_forward->bind_sockfd, port_forward->local_port); 575 | accept_fd = accept(port_forward->bind_sockfd, NULL, NULL); 576 | if(accept_fd != -1) 577 | { 578 | log_printf(L_INFO, "Accepting a new connection - requesting tunnel...\n"); 579 | 580 | /* Open a new tunnel for this FD */ 581 | port_forward->accept_sockfd = accept_fd; 582 | send_tunnel_request_packet( 583 | port_forward->remote_host, 584 | port_forward->remote_port, 585 | port_forward->forward_id, 586 | friendnumber 587 | ); 588 | } 589 | else 590 | { 591 | if(errno != EAGAIN && errno != EWOULDBLOCK) 592 | { 593 | log_printf(L_DEBUG, "Accept failed: code=%d (%s)\n", errno, strerror(errno)); 594 | } 595 | else 596 | { 597 | log_printf(L_DEBUG2, "Accept would block, no incoming connection right now\n"); 598 | } 599 | } 600 | } 601 | } 602 | 603 | /* Handle reading from sockets */ 604 | select_rv = select(client_select_nfds, &fds, NULL, NULL, &tv); 605 | if(select_rv == -1 || select_rv == 0) 606 | { 607 | if(select_rv == -1) 608 | { 609 | log_printf(L_DEBUG, "Reading from local socket failed: code=%d (%s)\n", 610 | errno, strerror(errno)); 611 | } 612 | else 613 | { 614 | log_printf(L_DEBUG2, "Nothing to read..."); 615 | } 616 | } 617 | else 618 | { 619 | HASH_ITER(hh, by_id, tun, tmp) 620 | { 621 | if(FD_ISSET(tun->sockfd, &fds)) 622 | { 623 | int nbytes; 624 | if(client_local_port_mode) 625 | { 626 | nbytes = recv(tun->sockfd, 627 | tox_packet_buf + PROTOCOL_BUFFER_OFFSET, 628 | READ_BUFFER_SIZE, 0); 629 | } 630 | else 631 | { 632 | nbytes = read(tun->sockfd, 633 | tox_packet_buf + PROTOCOL_BUFFER_OFFSET, 634 | READ_BUFFER_SIZE 635 | ); 636 | } 637 | 638 | /* Check if connection closed */ 639 | if(nbytes == 0) 640 | { 641 | uint8_t data[PROTOCOL_BUFFER_OFFSET]; 642 | protocol_frame frame_st, *frame; 643 | 644 | log_printf(L_INFO, "Connection closed\n"); 645 | 646 | frame = &frame_st; 647 | memset(frame, 0, sizeof(protocol_frame)); 648 | frame->friendnumber = tun->friendnumber; 649 | frame->packet_type = PACKET_TYPE_TCP_FIN; 650 | frame->connid = tun->connid; 651 | frame->data_length = 0; 652 | send_frame(frame, data); 653 | if(tun->sockfd) 654 | { 655 | FD_CLR(tun->sockfd, &client_master_fdset); 656 | } 657 | tunnel_delete(tun); 658 | } 659 | else 660 | { 661 | protocol_frame frame_st, *frame; 662 | 663 | frame = &frame_st; 664 | memset(frame, 0, sizeof(protocol_frame)); 665 | frame->friendnumber = tun->friendnumber; 666 | frame->packet_type = PACKET_TYPE_TCP; 667 | frame->connid = tun->connid; 668 | frame->data_length = nbytes; 669 | send_frame(frame, tox_packet_buf); 670 | 671 | log_printf(L_DEBUG2, "Wrote %d bytes from sock %d to tunnel %d\n", nbytes, tun->sockfd, tun->connid); 672 | } 673 | } 674 | } 675 | } 676 | 677 | fds = client_master_fdset; 678 | } 679 | break; 680 | case CLIENT_STATE_CONNECTION_LOST: 681 | { 682 | TOX_CONNECTION friend_connection_status; 683 | friend_connection_status = tox_friend_get_connection_status(tox, friendnumber, &friend_query_error); 684 | if(friend_query_error != TOX_ERR_FRIEND_QUERY_OK) 685 | { 686 | log_printf(L_DEBUG, "tox_friend_get_connection_status: error %u\n", friend_query_error); 687 | } 688 | else 689 | { 690 | if(friend_connection_status == TOX_CONNECTION_NONE) 691 | { 692 | /* https://github.com/TokTok/c-toxcore/blob/acb6b2d8543c8f2ea0c2e60dc046767cf5cc0de8/toxcore/tox.h#L1267 */ 693 | TOX_ERR_FRIEND_DELETE tox_delete_error; 694 | 695 | log_printf(L_WARNING, "Lost connection to server, closing all tunnels and re-adding friend\n"); 696 | client_close_all_connections(); 697 | tox_friend_delete(tox, friendnumber, &tox_delete_error); 698 | if(tox_delete_error) 699 | { 700 | log_printf(L_ERROR, "Error when deleting server from friend list: %d\n", tox_delete_error); 701 | } 702 | state = CLIENT_STATE_INITIAL; 703 | } 704 | else 705 | { 706 | state = CLIENT_STATE_FORWARDING; 707 | log_printf(L_DEBUG2, "Entered CLIENT_STATE_FORWARDING"); 708 | } 709 | } 710 | } 711 | break; 712 | case 0xffffffff: 713 | log_printf(L_ERROR, "You forgot a break statement\n"); 714 | exit(0); 715 | break; 716 | case CLIENT_STATE_SHUTDOWN: 717 | exit(0); 718 | break; 719 | } 720 | 721 | usleep(tox_iteration_interval(tox) * 1000); 722 | } 723 | } 724 | 725 | -------------------------------------------------------------------------------- /client.h: -------------------------------------------------------------------------------- 1 | #include "main.h" 2 | 3 | #define CLIENT_STATE_INITIAL 1 4 | #define CLIENT_STATE_SENTREQUEST 2 5 | #define CLIENT_STATE_REQUEST_ACCEPTED 3 6 | #define CLIENT_STATE_PING_SENT 4 7 | #define CLIENT_STATE_CONNECTED 5 8 | #define CLIENT_STATE_PONG_RECEIVED 6 9 | #define CLIENT_STATE_SEND_PING 7 10 | #define CLIENT_STATE_REQUEST_TUNNEL 8 11 | #define CLIENT_STATE_WAIT_FOR_ACKTUNNEL 9 12 | #define CLIENT_STATE_FORWARDING 10 13 | #define CLIENT_STATE_SHUTDOWN 11 14 | #define CLIENT_STATE_BIND_PORT 12 15 | #define CLIENT_STATE_SETUP_PIPE 13 16 | #define CLIENT_STATE_CONNECTION_LOST 14 17 | 18 | int handle_pong_frame(); 19 | int handle_acktunnel_frame(protocol_frame *rcvd_frame); 20 | int handle_server_tcp_frame(protocol_frame *rcvd_frame); 21 | int handle_server_tcp_fin_frame(protocol_frame *rcvd_frame); 22 | int do_client_loop(uint8_t *tox_id_str); 23 | -------------------------------------------------------------------------------- /debian/README.Debian: -------------------------------------------------------------------------------- 1 | tuntox for Debian 2 | ---------------- 3 | 4 | 5 | 6 | -- GDR! Fri, 14 Aug 2020 10:06:39 +0000 7 | -------------------------------------------------------------------------------- /debian/README.source: -------------------------------------------------------------------------------- 1 | tuntox for Debian 2 | ---------------- 3 | 4 | 6 | 7 | 8 | 9 | -- GDR! Fri, 14 Aug 2020 10:06:39 +0000 10 | 11 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | tuntox (0.0.10.1-1) UNRELEASED; urgency=medium 2 | 3 | * Update to upstream 0.0.10.1 4 | 5 | -- GDR! Sun, 12 Jun 2022 13:22:47 +0200 6 | 7 | tuntox (0.0.9-1) unstable; urgency=medium 8 | 9 | * Initial release (Closes: #nnnn) 10 | 11 | -- GDR! Fri, 14 Aug 2020 10:06:39 +0000 12 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: tuntox 2 | Section: net 3 | Priority: optional 4 | Maintainer: GDR! 5 | Build-Depends: debhelper-compat (= 12), libtoxcore-dev, 6 | pkg-config, build-essential, make, libtoxcore-dev, 7 | python3-jinja2, python3-requests 8 | Standards-Version: 4.5.0 9 | Homepage: https://gdr.name/tuntox/ 10 | #Vcs-Browser: https://salsa.debian.org/debian/tuntox 11 | Vcs-Git: https://github.com/gjedeer/tuntox.git 12 | 13 | Package: tuntox 14 | Architecture: any 15 | Depends: ${shlibs:Depends}, ${misc:Depends} 16 | Description: 17 | 18 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: tuntox 3 | Upstream-Contact: gdr@gdr.name 4 | Source: https://github.com/gjedeer/tuntox 5 | 6 | Files: * 7 | Copyright: 2014-2020 GDR! 8 | License: GPL-3 9 | This program is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | . 14 | This package is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | . 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | . 22 | On Debian systems, the complete text of the GNU General 23 | Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". 24 | 25 | # If you want to use GPL v2 or later for the /debian/* files use 26 | # the following clauses, or change it to suit. Delete these two lines 27 | Files: debian/* 28 | Copyright: 2020 GDR! 29 | License: GPL-3+ 30 | This program is free software: you can redistribute it and/or modify 31 | it under the terms of the GNU General Public License as published by 32 | the Free Software Foundation, either version 3 of the License, or 33 | (at your option) any later version. 34 | . 35 | This package is distributed in the hope that it will be useful, 36 | but WITHOUT ANY WARRANTY; without even the implied warranty of 37 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 38 | GNU General Public License for more details. 39 | . 40 | You should have received a copy of the GNU General Public License 41 | along with this program. If not, see . 42 | . 43 | On Debian systems, the complete text of the GNU General 44 | Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". 45 | 46 | # Please also look if there are files or directories which have a 47 | # different copyright/license attached and list them here. 48 | # Please avoid picking licenses with terms that are more restrictive than the 49 | # packaged work, as it may make Debian's contributions unacceptable upstream. 50 | # 51 | # If you need, there are some extra license texts available in two places: 52 | # /usr/share/debhelper/dh_make/licenses/ 53 | # /usr/share/common-licenses/ 54 | -------------------------------------------------------------------------------- /debian/manpage.1.ex: -------------------------------------------------------------------------------- 1 | .\" Hey, EMACS: -*- nroff -*- 2 | .\" (C) Copyright 2020 GDR! , 3 | .\" 4 | .\" First parameter, NAME, should be all caps 5 | .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection 6 | .\" other parameters are allowed: see man(7), man(1) 7 | .TH Tuntox SECTION "August 14 2020" 8 | .\" Please adjust this date whenever revising the manpage. 9 | .\" 10 | .\" Some roff macros, for reference: 11 | .\" .nh disable hyphenation 12 | .\" .hy enable hyphenation 13 | .\" .ad l left justify 14 | .\" .ad b justify to both left and right margins 15 | .\" .nf disable filling 16 | .\" .fi enable filling 17 | .\" .br insert line break 18 | .\" .sp insert n+1 empty lines 19 | .\" for manpage-specific macros, see man(7) 20 | .SH NAME 21 | tuntox \- program to do something 22 | .SH SYNOPSIS 23 | .B tuntox 24 | .RI [ options ] " files" ... 25 | .br 26 | .B bar 27 | .RI [ options ] " files" ... 28 | .SH DESCRIPTION 29 | This manual page documents briefly the 30 | .B tuntox 31 | and 32 | .B bar 33 | commands. 34 | .PP 35 | .\" TeX users may be more comfortable with the \fB\fP and 36 | .\" \fI\fP escape sequences to invode bold face and italics, 37 | .\" respectively. 38 | \fBtuntox\fP is a program that... 39 | .SH OPTIONS 40 | These programs follow the usual GNU command line syntax, with long 41 | options starting with two dashes (`-'). 42 | A summary of options is included below. 43 | For a complete description, see the Info files. 44 | .TP 45 | .B \-h, \-\-help 46 | Show summary of options. 47 | .TP 48 | .B \-v, \-\-version 49 | Show version of program. 50 | .SH SEE ALSO 51 | .BR bar (1), 52 | .BR baz (1). 53 | .br 54 | The programs are documented fully by 55 | .IR "The Rise and Fall of a Fooish Bar" , 56 | available via the Info system. 57 | -------------------------------------------------------------------------------- /debian/manpage.sgml.ex: -------------------------------------------------------------------------------- 1 | manpage.1'. You may view 5 | the manual page with: `docbook-to-man manpage.sgml | nroff -man | 6 | less'. A typical entry in a Makefile or Makefile.am is: 7 | 8 | manpage.1: manpage.sgml 9 | docbook-to-man $< > $@ 10 | 11 | 12 | The docbook-to-man binary is found in the docbook-to-man package. 13 | Please remember that if you create the nroff version in one of the 14 | debian/rules file targets (such as build), you will need to include 15 | docbook-to-man in your Build-Depends control field. 16 | 17 | --> 18 | 19 | 20 | FIRSTNAME"> 21 | SURNAME"> 22 | 23 | August 14 2020"> 24 | 26 | SECTION"> 27 | gdr@gdr.name"> 28 | 29 | Tuntox"> 30 | 31 | 32 | Debian"> 33 | GNU"> 34 | GPL"> 35 | ]> 36 | 37 | 38 | 39 |
40 | &dhemail; 41 |
42 | 43 | &dhfirstname; 44 | &dhsurname; 45 | 46 | 47 | 2003 48 | &dhusername; 49 | 50 | &dhdate; 51 |
52 | 53 | &dhucpackage; 54 | 55 | &dhsection; 56 | 57 | 58 | &dhpackage; 59 | 60 | program to do something 61 | 62 | 63 | 64 | &dhpackage; 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | DESCRIPTION 73 | 74 | This manual page documents briefly the 75 | &dhpackage; and bar 76 | commands. 77 | 78 | This manual page was written for the &debian; distribution 79 | because the original program does not have a manual page. 80 | Instead, it has documentation in the &gnu; 81 | Info format; see below. 82 | 83 | &dhpackage; is a program that... 84 | 85 | 86 | 87 | OPTIONS 88 | 89 | These programs follow the usual &gnu; command line syntax, 90 | with long options starting with two dashes (`-'). A summary of 91 | options is included below. For a complete description, see the 92 | Info files. 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | Show summary of options. 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | Show version of program. 109 | 110 | 111 | 112 | 113 | 114 | SEE ALSO 115 | 116 | bar (1), baz (1). 117 | 118 | The programs are documented fully by The Rise and 119 | Fall of a Fooish Bar available via the 120 | Info system. 121 | 122 | 123 | AUTHOR 124 | 125 | This manual page was written by &dhusername; &dhemail; for 126 | the &debian; system (and may be used by others). Permission is 127 | granted to copy, distribute and/or modify this document under 128 | the terms of the &gnu; General Public License, Version 2 any 129 | later version published by the Free Software Foundation. 130 | 131 | 132 | On Debian systems, the complete text of the GNU General Public 133 | License can be found in /usr/share/common-licenses/GPL. 134 | 135 | 136 | 137 |
138 | 139 | 155 | -------------------------------------------------------------------------------- /debian/manpage.xml.ex: -------------------------------------------------------------------------------- 1 | 2 | .
will be generated. You may view the 15 | manual page with: nroff -man .
| less'. A typical entry 16 | in a Makefile or Makefile.am is: 17 | 18 | DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/docbook-xsl/manpages/docbook.xsl 19 | XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" 20 | 21 | manpage.1: manpage.xml 22 | $(XP) $(DB2MAN) $< 23 | 24 | The xsltproc binary is found in the xsltproc package. The XSL files are in 25 | docbook-xsl. A description of the parameters you can use can be found in the 26 | docbook-xsl-doc-* packages. Please remember that if you create the nroff 27 | version in one of the debian/rules file targets (such as build), you will need 28 | to include xsltproc and docbook-xsl in your Build-Depends control field. 29 | Alternatively use the xmlto command/package. That will also automatically 30 | pull in xsltproc and docbook-xsl. 31 | 32 | Notes for using docbook2x: docbook2x-man does not automatically create the 33 | AUTHOR(S) and COPYRIGHT sections. In this case, please add them manually as 34 | ... . 35 | 36 | To disable the automatic creation of the AUTHOR(S) and COPYRIGHT sections 37 | read /usr/share/doc/docbook-xsl/doc/manpages/authors.html. This file can be 38 | found in the docbook-xsl-doc-html package. 39 | 40 | Validation can be done using: `xmllint -''-noout -''-valid manpage.xml` 41 | 42 | General documentation about man-pages and man-page-formatting: 43 | man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ 44 | 45 | --> 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 56 | 57 | 59 | 60 | 61 | 62 | ]> 63 | 64 | 65 | 66 | &dhtitle; 67 | &dhpackage; 68 | 69 | 70 | &dhfirstname; 71 | &dhsurname; 72 | Wrote this manpage for the Debian system. 73 |
74 | &dhemail; 75 |
76 |
77 |
78 | 79 | 2007 80 | &dhusername; 81 | 82 | 83 | This manual page was written for the Debian system 84 | (and may be used by others). 85 | Permission is granted to copy, distribute and/or modify this 86 | document under the terms of the GNU General Public License, 87 | Version 2 or (at your option) any later version published by 88 | the Free Software Foundation. 89 | On Debian systems, the complete text of the GNU General Public 90 | License can be found in 91 | /usr/share/common-licenses/GPL. 92 | 93 |
94 | 95 | &dhucpackage; 96 | &dhsection; 97 | 98 | 99 | &dhpackage; 100 | program to do something 101 | 102 | 103 | 104 | &dhpackage; 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | this 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | this 122 | that 123 | 124 | 125 | 126 | 127 | &dhpackage; 128 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | DESCRIPTION 148 | This manual page documents briefly the 149 | &dhpackage; and bar 150 | commands. 151 | This manual page was written for the Debian distribution 152 | because the original program does not have a manual page. 153 | Instead, it has documentation in the GNU 154 | info 155 | 1 156 | format; see below. 157 | &dhpackage; is a program that... 158 | 159 | 160 | OPTIONS 161 | The program follows the usual GNU command line syntax, 162 | with long options starting with two dashes (`-'). A summary of 163 | options is included below. For a complete description, see the 164 | 165 | info 166 | 1 167 | files. 168 | 169 | 172 | 173 | 174 | 175 | 176 | Does this and that. 177 | 178 | 179 | 180 | 181 | 182 | 183 | Show summary of options. 184 | 185 | 186 | 187 | 188 | 189 | 190 | Show version of program. 191 | 192 | 193 | 194 | 195 | 196 | FILES 197 | 198 | 199 | /etc/foo.conf 200 | 201 | The system-wide configuration file to control the 202 | behaviour of &dhpackage;. See 203 | 204 | foo.conf 205 | 5 206 | for further details. 207 | 208 | 209 | 210 | ${HOME}/.foo.conf 211 | 212 | The per-user configuration file to control the 213 | behaviour of &dhpackage;. See 214 | 215 | foo.conf 216 | 5 217 | for further details. 218 | 219 | 220 | 221 | 222 | 223 | ENVIRONMENT 224 | 225 | 226 | FOO_CONF 227 | 228 | If used, the defined file is used as configuration 229 | file (see also ). 230 | 231 | 232 | 233 | 234 | 235 | DIAGNOSTICS 236 | The following diagnostics may be issued 237 | on stderr: 238 | 239 | 240 | Bad configuration file. Exiting. 241 | 242 | The configuration file seems to contain a broken configuration 243 | line. Use the option, to get more info. 244 | 245 | 246 | 247 | 248 | &dhpackage; provides some return codes, that can 249 | be used in scripts: 250 | 251 | Code 252 | Diagnostic 253 | 254 | 0 255 | Program exited successfully. 256 | 257 | 258 | 1 259 | The configuration file seems to be broken. 260 | 261 | 262 | 263 | 264 | 265 | BUGS 266 | The program is currently limited to only work 267 | with the foobar library. 268 | The upstreams BTS can be found 269 | at . 270 | 271 | 272 | SEE ALSO 273 | 274 | 275 | bar 276 | 1 277 | , 278 | baz 279 | 1 280 | , 281 | foo.conf 282 | 5 283 | 284 | The programs are documented fully by The Rise and 285 | Fall of a Fooish Bar available via the 286 | info 287 | 1 288 | system. 289 | 290 |
291 | 292 | -------------------------------------------------------------------------------- /debian/postinst.ex: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # postinst script for tuntox 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # summary of how this script can be called: 9 | # * `configure' 10 | # * `abort-upgrade' 11 | # * `abort-remove' `in-favour' 12 | # 13 | # * `abort-remove' 14 | # * `abort-deconfigure' `in-favour' 15 | # `removing' 16 | # 17 | # for details, see https://www.debian.org/doc/debian-policy/ or 18 | # the debian-policy package 19 | 20 | 21 | case "$1" in 22 | configure) 23 | ;; 24 | 25 | abort-upgrade|abort-remove|abort-deconfigure) 26 | ;; 27 | 28 | *) 29 | echo "postinst called with unknown argument \`$1'" >&2 30 | exit 1 31 | ;; 32 | esac 33 | 34 | # dh_installdeb will replace this with shell code automatically 35 | # generated by other debhelper scripts. 36 | 37 | #DEBHELPER# 38 | 39 | exit 0 40 | -------------------------------------------------------------------------------- /debian/postrm.ex: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # postrm script for tuntox 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # summary of how this script can be called: 9 | # * `remove' 10 | # * `purge' 11 | # * `upgrade' 12 | # * `failed-upgrade' 13 | # * `abort-install' 14 | # * `abort-install' 15 | # * `abort-upgrade' 16 | # * `disappear' 17 | # 18 | # for details, see https://www.debian.org/doc/debian-policy/ or 19 | # the debian-policy package 20 | 21 | 22 | case "$1" in 23 | purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) 24 | ;; 25 | 26 | *) 27 | echo "postrm called with unknown argument \`$1'" >&2 28 | exit 1 29 | ;; 30 | esac 31 | 32 | # dh_installdeb will replace this with shell code automatically 33 | # generated by other debhelper scripts. 34 | 35 | #DEBHELPER# 36 | 37 | exit 0 38 | -------------------------------------------------------------------------------- /debian/preinst.ex: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # preinst script for tuntox 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # summary of how this script can be called: 9 | # * `install' 10 | # * `install' 11 | # * `upgrade' 12 | # * `abort-upgrade' 13 | # for details, see https://www.debian.org/doc/debian-policy/ or 14 | # the debian-policy package 15 | 16 | 17 | case "$1" in 18 | install|upgrade) 19 | ;; 20 | 21 | abort-upgrade) 22 | ;; 23 | 24 | *) 25 | echo "preinst called with unknown argument \`$1'" >&2 26 | exit 1 27 | ;; 28 | esac 29 | 30 | # dh_installdeb will replace this with shell code automatically 31 | # generated by other debhelper scripts. 32 | 33 | #DEBHELPER# 34 | 35 | exit 0 36 | -------------------------------------------------------------------------------- /debian/prerm.ex: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # prerm script for tuntox 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | # summary of how this script can be called: 9 | # * `remove' 10 | # * `upgrade' 11 | # * `failed-upgrade' 12 | # * `remove' `in-favour' 13 | # * `deconfigure' `in-favour' 14 | # `removing' 15 | # 16 | # for details, see https://www.debian.org/doc/debian-policy/ or 17 | # the debian-policy package 18 | 19 | 20 | case "$1" in 21 | remove|upgrade|deconfigure) 22 | ;; 23 | 24 | failed-upgrade) 25 | ;; 26 | 27 | *) 28 | echo "prerm called with unknown argument \`$1'" >&2 29 | exit 1 30 | ;; 31 | esac 32 | 33 | # dh_installdeb will replace this with shell code automatically 34 | # generated by other debhelper scripts. 35 | 36 | #DEBHELPER# 37 | 38 | exit 0 39 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # See debhelper(7) (uncomment to enable) 3 | # output every command that modifies files on the build system. 4 | #export DH_VERBOSE = 1 5 | 6 | 7 | # see FEATURE AREAS in dpkg-buildflags(1) 8 | #export DEB_BUILD_MAINT_OPTIONS = hardening=+all 9 | 10 | # see ENVIRONMENT in dpkg-buildflags(1) 11 | # package maintainers to append CFLAGS 12 | #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic 13 | # package maintainers to append LDFLAGS 14 | #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed 15 | 16 | 17 | %: 18 | dh $@ 19 | 20 | 21 | # dh_make generated override targets 22 | # This is example for Cmake (See https://bugs.debian.org/641051 ) 23 | #override_dh_auto_configure: 24 | # dh_auto_configure -- # -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH) 25 | 26 | -------------------------------------------------------------------------------- /debian/salsa-ci.yml.ex: -------------------------------------------------------------------------------- 1 | # For more information on what jobs are run see: 2 | # https://salsa.debian.org/salsa-ci-team/pipeline 3 | # 4 | # To enable the jobs, go to your repository (at salsa.debian.org) 5 | # and click over Settings > CI/CD > Expand (in General pipelines). 6 | # In "Custom CI config path" write debian/salsa-ci.yml and click 7 | # in "Save Changes". The CI tests will run after the next commit. 8 | --- 9 | include: 10 | - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml 11 | - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml 12 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/tuntox-docs.docs: -------------------------------------------------------------------------------- 1 | README.Debian 2 | README.source 3 | -------------------------------------------------------------------------------- /debian/tuntox.cron.d.ex: -------------------------------------------------------------------------------- 1 | # 2 | # Regular cron jobs for the tuntox package 3 | # 4 | 0 4 * * * root [ -x /usr/bin/tuntox_maintenance ] && /usr/bin/tuntox_maintenance 5 | -------------------------------------------------------------------------------- /debian/tuntox.doc-base.EX: -------------------------------------------------------------------------------- 1 | Document: tuntox 2 | Title: Debian tuntox Manual 3 | Author: 4 | Abstract: This manual describes what tuntox is 5 | and how it can be used to 6 | manage online manuals on Debian systems. 7 | Section: unknown 8 | 9 | Format: debiandoc-sgml 10 | Files: /usr/share/doc/tuntox/tuntox.sgml.gz 11 | 12 | Format: postscript 13 | Files: /usr/share/doc/tuntox/tuntox.ps.gz 14 | 15 | Format: text 16 | Files: /usr/share/doc/tuntox/tuntox.text.gz 17 | 18 | Format: HTML 19 | Index: /usr/share/doc/tuntox/html/index.html 20 | Files: /usr/share/doc/tuntox/html/*.html 21 | -------------------------------------------------------------------------------- /debian/watch.ex: -------------------------------------------------------------------------------- 1 | # Example watch control file for uscan 2 | # Rename this file to "watch" and then you can run the "uscan" command 3 | # to check for upstream updates and more. 4 | # See uscan(1) for format 5 | 6 | # Compulsory line, this is a version 4 file 7 | version=4 8 | 9 | # PGP signature mangle, so foo.tar.gz has foo.tar.gz.sig 10 | #opts="pgpsigurlmangle=s%$%.sig%" 11 | 12 | # HTTP site (basic) 13 | #http://example.com/downloads.html \ 14 | # files/tuntox-([\d\.]+)\.tar\.gz debian uupdate 15 | 16 | # Uncomment to examine an FTP server 17 | #ftp://ftp.example.com/pub/tuntox-(.*)\.tar\.gz debian uupdate 18 | 19 | # SourceForge hosted projects 20 | # http://sf.net/tuntox/ tuntox-(.*)\.tar\.gz debian uupdate 21 | 22 | # GitHub hosted projects 23 | #opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%-$1.tar.gz%" \ 24 | # https://github.com//tuntox/tags \ 25 | # (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate 26 | 27 | # PyPI 28 | # https://pypi.debian.net/tuntox/tuntox-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz))) 29 | 30 | # Direct Git 31 | # opts="mode=git" http://git.example.com/tuntox.git \ 32 | # refs/tags/v([\d\.]+) debian uupdate 33 | 34 | 35 | 36 | 37 | # Uncomment to find new files on GooglePages 38 | # http://example.googlepages.com/foo.html tuntox-(.*)\.tar\.gz 39 | -------------------------------------------------------------------------------- /freebsd/Makefile: -------------------------------------------------------------------------------- 1 | # New ports collection Makefile for: tuntox 2 | # Date created: 2023-09-28 3 | # Whom: GDR! 4 | # 5 | # $FreeBSD$ 6 | # 7 | 8 | PORTNAME= tuntox 9 | PORTVERSION= 0.0.10.1 10 | CATEGORIES= net-p2p 11 | MASTER_SITES= GH 12 | PKGNAMEPREFIX= ${PORTNAME}- 13 | 14 | MAINTAINER= gdr@gdr.name 15 | COMMENT= Tunnel TCP connections over the Tox protocol 16 | 17 | LICENSE= GPLv3 18 | LICENSE_FILE= ${WRKSRC}/LICENSE.md 19 | 20 | BUILD_DEPENDS= /usr/local/lib/libtoxcore.so.2:net-im/tox 21 | BUILD_DEPENDS+= git:devel/git 22 | 23 | RUN_DEPENDS= /usr/local/lib/libtoxcore.so.2:net-im/tox 24 | 25 | USES= gmake 26 | 27 | USE_GITHUB= yes 28 | GH_ACCOUNT= gjedeer 29 | GH_PROJECT= tuntox 30 | GH_TAGNAME= 0adadfebed9bd4a9ffb22e5d248767b32f312a6a 31 | 32 | PLIST_FILES= bin/tuntox 33 | 34 | do-build: 35 | @(cd ${WRKSRC} && ${SETENV} ${MAKE_ENV} ${MAKE_CMD} tuntox_nostatic) 36 | 37 | do-install: 38 | ${INSTALL_PROGRAM} ${WRKSRC}/tuntox_nostatic ${STAGEDIR}${PREFIX}/bin/tuntox 39 | 40 | 41 | .include 42 | -------------------------------------------------------------------------------- /freebsd/README.md: -------------------------------------------------------------------------------- 1 | # FreeBSD Port Maintainer Wanted 2 | 3 | I wrote a Makefile for FreeBSD ports but don't feel like becoming an official maintainer. If you feel like maintaining it, just see how lethargic the development of tuntox is, it will take an hour of two of your time per year. Chance is that all you're going to do is bump version numbers. 4 | 5 | ``` 6 | mkdir /usr/ports/net-p2p/tuntox/ 7 | cd /usr/ports/net-p2p/tuntox/ 8 | wget https://github.com/gjedeer/tuntox/raw/master/freebsd/distinfo 9 | wget https://github.com/gjedeer/tuntox/raw/master/freebsd/Makefile 10 | wget https://github.com/gjedeer/tuntox/raw/master/freebsd/pkg-descr 11 | make 12 | ``` 13 | -------------------------------------------------------------------------------- /freebsd/distinfo: -------------------------------------------------------------------------------- 1 | TIMESTAMP = 1695974593 2 | SHA256 (gjedeer-tuntox-0.0.10.1-0adadfebed9bd4a9ffb22e5d248767b32f312a6a_GH0.tar.gz) = 79681c274483d8048d42d288b63d9619bbcbae5a520958df3e1b5efda000be16 3 | SIZE (gjedeer-tuntox-0.0.10.1-0adadfebed9bd4a9ffb22e5d248767b32f312a6a_GH0.tar.gz) = 243248 4 | -------------------------------------------------------------------------------- /freebsd/pkg-descr: -------------------------------------------------------------------------------- 1 | Tuntox is a program which forwards TCP connections over the Tox protocol. This allows low-latency access to distant machines behind a NAT you can't control or with a dynamic IP address. 2 | 3 | WWW: https://gdr.name/tuntox/ 4 | -------------------------------------------------------------------------------- /generate_tox_bootstrap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # pip3 install jinja2 requests 3 | 4 | import datetime 5 | import jinja2 6 | import json 7 | import requests 8 | import socket 9 | 10 | json_url = 'https://nodes.tox.chat/json' 11 | 12 | tox_bootstrap_template = """ 13 | /* 14 | * Generated with generate_tox_bootstrap.py by GDR! 15 | * from {{ json_url }} on {{ now }} 16 | */ 17 | struct bootstrap_node { 18 | char *address; 19 | uint16_t port; 20 | uint8_t key[32]; 21 | } bootstrap_nodes[] = { 22 | {% for node in nodes %} 23 | { 24 | "{{ node.ip }}", 25 | {{ node.port }}, 26 | { 27 | {{ node.public_key|toxtoc }} 28 | } 29 | }, 30 | {% endfor %} 31 | }; 32 | 33 | struct bootstrap_node tcp_relays[] = { 34 | {% for node in relays %} 35 | { 36 | "{{ node.ip }}", 37 | {{ node.port }}, 38 | { 39 | {{ node.public_key|toxtoc }} 40 | } 41 | }, 42 | {% endfor %} 43 | }; 44 | """ 45 | 46 | def toxtoc(value): 47 | """ 48 | A Jinja2 filter to turn a ToxID into two lines of C bytes 49 | """ 50 | def get_16_bytes(value): 51 | """ 52 | Generate 1 line of C code - 16 bytes 53 | @param value a hex string of length 32 (32 hex chars) 54 | """ 55 | if len(value) != 32: 56 | raise ValueError('%r is not a 32-char string') 57 | 58 | rv = "" 59 | 60 | for i in range(16): 61 | rv += "0x%s" % value[2*i : 2*i+2] 62 | if i < 15: 63 | rv += ", " 64 | 65 | return rv 66 | 67 | rv = get_16_bytes(value[:32]) + \ 68 | ",\n" + (12*' ') + \ 69 | get_16_bytes(value[32:]) 70 | 71 | return rv 72 | 73 | class Loader(jinja2.BaseLoader): 74 | def get_source(self, environment, template): 75 | return tox_bootstrap_template, 'tox_bootstrap_template', True 76 | 77 | if __name__ == "__main__": 78 | r = requests.get(json_url) 79 | data = r.json() 80 | if 'nodes' not in data: 81 | raise ValueError('nodes element not in JSON') 82 | 83 | nodes = [] 84 | tcp_relays = [] 85 | 86 | for elem in data['nodes']: 87 | node = {} 88 | if ('ipv4' not in elem and 'ipv6' not in elem) or 'port' not in elem or 'public_key' not in elem: 89 | print("SKIPPING", elem) 90 | continue 91 | 92 | if len(elem['public_key']) != 64: 93 | print("Bad public key %s, skipping!" % elem['public_key']) 94 | continue 95 | 96 | node['port'] = int(elem['port']) 97 | node['public_key'] = elem['public_key'] 98 | 99 | for addr, family in ( 100 | (elem.get('ipv4', ''), socket.AF_INET), 101 | (elem.get('ipv6', ''), socket.AF_INET6), 102 | ): 103 | if not addr.strip() or addr == '-': 104 | continue 105 | try: 106 | socket.inet_pton(family, addr) 107 | node['ip'] = addr 108 | except socket.error: 109 | # IPv4 is not numeric, let's try resolving 110 | try: 111 | print("RESOLVING", addr) 112 | node['ip'] = socket.gethostbyname(addr) 113 | except socket.error: 114 | print("Could not resolve ip: %s, skipping!" % addr) 115 | continue 116 | 117 | if 'status_udp' in elem and elem['status_udp']: 118 | nodes.append(node) 119 | 120 | if 'tcp_ports' in elem and elem['tcp_ports'] and \ 121 | 'status_tcp' in elem and elem['status_tcp']: 122 | for port in elem['tcp_ports']: 123 | relay = dict(node) 124 | try: 125 | relay['port'] = int(port) 126 | except ValueError: 127 | continue 128 | 129 | tcp_relays.append(relay) 130 | 131 | env = jinja2.Environment(loader=Loader()) 132 | env.filters['toxtoc'] = toxtoc 133 | template = env.get_template('tox_bootstrap_template') 134 | tox_bootstrap_h = template.render(nodes=nodes, now=datetime.datetime.now(), json_url=json_url, relays=tcp_relays) 135 | open('tox_bootstrap.h', 'w').write(tox_bootstrap_h) 136 | 137 | -------------------------------------------------------------------------------- /gitversion.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "gitversion.h" 3 | #include "log.h" 4 | 5 | const char *gitversion = GITVERSION; 6 | 7 | void print_version() 8 | { 9 | log_printf(L_INFO, "Tuntox built from git commit %s, toxcore version %d.%d.%d, protocol version 2", gitversion, tox_version_major(), tox_version_minor(), tox_version_patch()); 10 | } 11 | 12 | void print_version_stdout() 13 | { 14 | printf("Tuntox built from git commit %s, toxcore version %d.%d.%d\n", gitversion, tox_version_major(), tox_version_minor(), tox_version_patch()); 15 | } 16 | -------------------------------------------------------------------------------- /gitversion.h: -------------------------------------------------------------------------------- 1 | #define GITVERSION "1f3cb8e35d37333f34b7deba636b80cb25b24801" 2 | -------------------------------------------------------------------------------- /log.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "log.h" 9 | 10 | /* 11 | * The minimum log level; set to one of L_* constants from log.h 12 | */ 13 | int min_log_level = 666; 14 | 15 | /* 16 | * 0: send output to stderr 17 | * 1: send output to syslog LOG_LOCAL1 facility 18 | */ 19 | int use_syslog = 0; 20 | 21 | /* 22 | * 0: don't display toxcore TRACE messages 23 | * 1: display all toxcore messages 24 | */ 25 | int log_tox_trace = 0; 26 | 27 | /* Turn log level number to a printable string */ 28 | char *log_printable_level(int level) 29 | { 30 | switch(level) 31 | { 32 | case L_ERROR: 33 | return "ERROR"; 34 | case L_WARNING: 35 | return "WARNING"; 36 | case L_NOTICE: 37 | return "NOTICE"; 38 | case L_INFO: 39 | return "INFO"; 40 | case L_DEBUG: 41 | return "DEBUG"; 42 | case L_DEBUG2: 43 | return "DEBUG2"; 44 | } 45 | return "UNKNOWN"; 46 | } 47 | 48 | void log_init(void) 49 | { 50 | if(use_syslog) 51 | { 52 | openlog("tuntox", LOG_PID, LOG_LOCAL1); 53 | } 54 | } 55 | 56 | void log_close(void) 57 | { 58 | if(use_syslog) 59 | { 60 | closelog(); 61 | } 62 | } 63 | 64 | /* Output the log to the console */ 65 | void log_printf(int level, const char *fmt, ...) 66 | { 67 | va_list args; 68 | char logfmt[2048]; 69 | char logtime[100]; 70 | char *level_str; 71 | time_t rawtime; 72 | struct tm *timeinfo; 73 | 74 | if(level > min_log_level) 75 | { 76 | return; 77 | } 78 | 79 | if(!use_syslog) 80 | { 81 | time(&rawtime); 82 | timeinfo = localtime(&rawtime); 83 | strftime(logtime, 100, "%F %X", timeinfo); 84 | 85 | level_str = log_printable_level(level); 86 | 87 | if(fmt[strlen(fmt)-1] == '\n') 88 | { 89 | snprintf(logfmt, 2048, "%s: [%s]\t%s", logtime, level_str, fmt); 90 | } 91 | else 92 | { 93 | snprintf(logfmt, 2048, "%s: [%s]\t%s\n", logtime, level_str, fmt); 94 | } 95 | 96 | va_start(args, fmt); 97 | vfprintf(stderr, logfmt, args); 98 | va_end(args); 99 | } 100 | else 101 | { 102 | va_start(args, fmt); 103 | vsyslog(LOG_MAKEPRI(LOG_LOCAL1, level), fmt, args); 104 | va_end(args); 105 | } 106 | } 107 | 108 | 109 | void log_test(void) 110 | { 111 | int i = 112; 112 | char *x = "test"; 113 | 114 | log_printf(L_WARNING, "Testing"); 115 | log_printf(L_ERROR, "Number stodwadziesciatrzy: %d", 123); 116 | d(beenthere); 117 | dd(i); 118 | 119 | dp(&i); 120 | ds(x); 121 | } 122 | 123 | static const char *tox_log_level_name(TOX_LOG_LEVEL level) 124 | { 125 | switch (level) { 126 | case TOX_LOG_LEVEL_TRACE: 127 | return "TRACE"; 128 | 129 | case TOX_LOG_LEVEL_DEBUG: 130 | return "DEBUG"; 131 | 132 | case TOX_LOG_LEVEL_INFO: 133 | return "INFO"; 134 | 135 | case TOX_LOG_LEVEL_WARNING: 136 | return "WARNING"; 137 | 138 | case TOX_LOG_LEVEL_ERROR: 139 | return "ERROR"; 140 | } 141 | 142 | return "UNKNOWN"; 143 | } 144 | 145 | void on_tox_log(Tox *tox, TOX_LOG_LEVEL level, const char *path, uint32_t line, const char *func, 146 | const char *message, void *user_data) 147 | { 148 | uint32_t index = user_data ? *(uint32_t *)user_data : 0; 149 | const char *file = strrchr(path, '/'); 150 | 151 | if(level == TOX_LOG_LEVEL_TRACE && !log_tox_trace) 152 | { 153 | return; 154 | } 155 | 156 | file = file ? file + 1 : path; 157 | log_printf(L_DEBUG2, "[#%d] %s %s:%d\t%s:\t%s\n", index, tox_log_level_name(level), file, line, func, message); 158 | } 159 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define L_ERROR 3 4 | #define L_WARNING 4 5 | #define L_NOTICE 5 6 | #define L_INFO 6 7 | #define L_DEBUG 7 8 | #define L_DEBUG2 8 9 | 10 | #define L_UNSET 0x29a 11 | 12 | void log_printf(int level, const char *fmt, ...); 13 | void log_init(void); 14 | void log_close(void); 15 | void on_tox_log(Tox *tox, TOX_LOG_LEVEL level, const char *file, uint32_t line, const char *func, 16 | const char *message, void *user_data); 17 | 18 | extern int min_log_level; 19 | extern int use_syslog; 20 | extern int log_tox_trace; 21 | 22 | #define d(x) log_printf(L_DEBUG, "%s:%d %s", __FILE__, __LINE__, #x); 23 | 24 | /* Debug-log the int variable x */ 25 | #define dd(x) log_printf(L_DEBUG, "%s:%d %s=%d", __FILE__, __LINE__, #x, (x)); 26 | 27 | /* Debug-log the pointer variable x */ 28 | #define dp(x) log_printf(L_DEBUG, "%s:%d %s=%p", __FILE__, __LINE__, #x, (x)); 29 | 30 | /* Debug-log the string variable x */ 31 | #define ds(x) log_printf(L_DEBUG, "%s:%d %s=%s", __FILE__, __LINE__, #x, (x)); 32 | -------------------------------------------------------------------------------- /mach.h: -------------------------------------------------------------------------------- 1 | #ifndef _MACH_H 2 | #define _MACH_H 3 | 4 | #include 5 | #include 6 | 7 | // MacOS doesn't support the flag MSG_NOSIGNAL 8 | #define MSG_NOSIGNAL SO_NOSIGPIPE 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAIN_H 2 | #define _MAIN_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "util.h" 26 | #include "uthash.h" 27 | #include "utlist.h" 28 | 29 | 30 | #define PROTOCOL_MAGIC_V1 0xa26a 31 | #define PROTOCOL_MAGIC_V2 0xa26b 32 | #define PROTOCOL_MAGIC PROTOCOL_MAGIC_V2 33 | #define PROTOCOL_MAGIC_HIGH (PROTOCOL_MAGIC >> 8) 34 | #define PROTOCOL_MAGIC_LOW (PROTOCOL_MAGIC & 0xff) 35 | #define PACKET_TYPE_PONG 0x0100 36 | #define PACKET_TYPE_PING 0x0108 37 | #define PACKET_TYPE_REQUESTTUNNEL 0x0602 /* TODO - currently unused */ 38 | #define PACKET_TYPE_DENYTUNNEL 0x0604 39 | #define PACKET_TYPE_ACKTUNNEL 0x0610 40 | #define PACKET_TYPE_TCP 0x0600 41 | #define PACKET_TYPE_TCP_FIN 0x0601 42 | 43 | #define INT16_AT(array,pos) ( (*((array)+(pos)))*256 + (*((array)+(pos)+1)) ) 44 | #define INT32_AT(array,pos) ( (*((array)+(pos)))*256*256*256 + (*((array)+(pos)+1))*256*256 +(*((array)+(pos)+2))*256 + (*((array)+(pos)+3)) ) 45 | #define BYTE1(number) ((number)&0xff) 46 | #define BYTE2(number) (((number) / 256) & 0xff) 47 | #define BYTE3(number) (((number) / (256*256)) & 0xff) 48 | #define BYTE4(number) (((number) / (256*256*256)) & 0xff) 49 | 50 | /* Offset of the data buffer in the packet */ 51 | #define PROTOCOL_BUFFER_OFFSET 8 52 | #define READ_BUFFER_SIZE TOX_MAX_CUSTOM_PACKET_SIZE - PROTOCOL_BUFFER_OFFSET 53 | #define PROTOCOL_MAX_PACKET_SIZE (READ_BUFFER_SIZE + PROTOCOL_BUFFER_OFFSET) 54 | 55 | 56 | typedef struct tunnel_t { 57 | /* The forwarded socket fd */ 58 | int sockfd; 59 | /* Connection ID, must be int because of uthash */ 60 | int connid; 61 | /* Friend number of remote end */ 62 | uint32_t friendnumber; 63 | 64 | UT_hash_handle hh; 65 | } tunnel; 66 | 67 | typedef struct tunnel_list_t { 68 | tunnel *tun; 69 | struct tunnel_list_t *next; 70 | } tunnel_list; 71 | 72 | typedef struct allowed_toxid { 73 | uint8_t toxid[TOX_ADDRESS_SIZE]; 74 | struct allowed_toxid *next; 75 | } allowed_toxid; 76 | 77 | typedef struct protocol_frame_t { 78 | uint32_t friendnumber; 79 | 80 | /* Fields actually found in the protocol */ 81 | uint16_t magic; 82 | uint16_t packet_type; 83 | uint16_t connid; 84 | uint16_t data_length; 85 | uint8_t *data; 86 | } protocol_frame; 87 | 88 | /* A list of local port forwards (listen locally, forward to server) */ 89 | typedef struct local_port_forward_t { 90 | int local_port; 91 | char *remote_host; 92 | int remote_port; 93 | 94 | /* Sock representing the local port - call accept() on it */ 95 | int bind_sockfd; 96 | 97 | /* If tunnel open is pending, accepted sockfd is temporarly stored here */ 98 | /* -1 = we can accept another connection */ 99 | int accept_sockfd; 100 | 101 | /* When the forward has been created - used in ack timeouts */ 102 | time_t created; 103 | 104 | /* ID - used to identify the ack frame */ 105 | uint32_t forward_id; 106 | 107 | struct local_port_forward_t *next; 108 | } local_port_forward; 109 | 110 | /* Rules policy */ 111 | enum rules_policy_enum { VALIDATE, NONE }; 112 | typedef struct rule { 113 | uint16_t port; 114 | char * host; 115 | struct rule *next; 116 | } rule; 117 | 118 | /**** GLOBAL VARIABLES ****/ 119 | extern Tox *tox; 120 | /* Whether we're a client */ 121 | extern int client_mode; 122 | /* Just send a ping and exit */ 123 | extern int ping_mode; 124 | /* TOX_CONNECTION global variable */ 125 | extern TOX_CONNECTION connection_status; 126 | /* Open a local port and forward it */ 127 | extern int client_local_port_mode; 128 | /* Forward stdin/stdout to remote machine - SSH ProxyCommand mode */ 129 | extern int client_pipe_mode; 130 | /* Remote Tox ID in client mode */ 131 | extern uint8_t *remote_tox_id; 132 | /* Ports and hostname for port forwarding */ 133 | extern int remote_port; 134 | extern char *remote_host; 135 | extern int local_port; 136 | /* Shared secret used for authentication */ 137 | extern int use_shared_secret; 138 | extern char shared_secret[TOX_MAX_FRIEND_REQUEST_LENGTH]; 139 | 140 | extern int select_nfds; 141 | extern tunnel *by_id; 142 | 143 | extern local_port_forward *local_port_forwards; 144 | 145 | local_port_forward *find_pending_forward_by_id(uint32_t local_forward_id); 146 | 147 | void parse_lossless_packet(Tox *tox, uint32_t friendnumber, const uint8_t *data, size_t len, void *tmp); 148 | tunnel *tunnel_create(int sockfd, int connid, uint32_t friendnumber); 149 | void tunnel_delete(tunnel *t); 150 | void update_select_nfds(int fd, fd_set *fds, int *old_select_nfds); 151 | int send_frame(protocol_frame *frame, uint8_t *data); 152 | int send_tunnel_request_packet(char *remote_host, int remote_port, uint32_t local_forward_id, int friend_number); 153 | 154 | void print_version(void); 155 | void print_version_stdout(void); 156 | #endif 157 | -------------------------------------------------------------------------------- /multiarch-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Needs https://github.com/tonistiigi/binfmt to work 4 | 5 | SRCDIR="`pwd`" 6 | BUILDDIR="$SRCDIR/multiarch-build" 7 | SRC_DOCKERFILE="$SRCDIR/Dockerfile" 8 | 9 | GIT_HASH=`git rev-parse --short HEAD` 10 | GIT_TAG=`git tag --contains $GIT_HASH` 11 | if [[ -z "$GIT_TAG" ]]; then 12 | PRINTABLE_VERSION=$GIT_HASH 13 | else 14 | PRINTABLE_VERSION=$GIT_TAG 15 | fi 16 | 17 | DOCKER_ID="gdr1/tuntox" 18 | 19 | if [ ! -d "$BUILDDIR" ]; then mkdir -p "$BUILDDIR"; fi 20 | 21 | cp -R "$SRCDIR/scripts" "$BUILDDIR/" 22 | 23 | for PLATFORM in arm32v6 arm32v7 arm64v8 amd64 arm32v5 ppc64le s390x mips64le riscv64 i386; do 24 | cd "$BUILDDIR" 25 | echo $PLATFORM; 26 | sed -e "s#alpine#$PLATFORM/alpine#g" <"$SRC_DOCKERFILE" >Dockerfile 27 | docker build -t $DOCKER_ID:$PLATFORM . 28 | docker run --rm -it $DOCKER_ID:$PLATFORM cat /usr/bin/tuntox >tuntox-$PRINTABLE_VERSION-linux-$PLATFORM 29 | done 30 | -------------------------------------------------------------------------------- /screenshots/wsl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gjedeer/tuntox/824babaac32c22f6c72a9eba5c54917eb8464ef7/screenshots/wsl.png -------------------------------------------------------------------------------- /scripts/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | tuntox: 4 | image: gdr1/tuntox 5 | container_name: tuntox 6 | environment: 7 | - TUNTOX_SHARED_SECRET=myassfeelsweird 8 | volumes: 9 | - /docker/tuntox:/data 10 | ports: 11 | - 33446:33446 12 | - 33446:33446/udp 13 | - 33447:33447/udp 14 | restart: always 15 | 16 | 17 | -------------------------------------------------------------------------------- /scripts/pre-push.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## hook to check version match tag before push 4 | ## usage: ln -s ../../scripts/pre-push.sh .git/hooks/pre-push 5 | 6 | VERSIONFILE="gitversion.h" 7 | BRANCH="HEAD" 8 | 9 | tagref=$(grep -Po 'refs/tags/([^ ]*) ' = 3.0-6) to ensure that this file is present. 48 | . /lib/lsb/init-functions 49 | 50 | mkdir -p /var/run/$NAME 51 | chown $USERID /var/run/$NAME 52 | 53 | # 54 | # Function that starts the daemon/service 55 | # 56 | do_start() 57 | { 58 | # Return value 59 | # 0 if daemon has been started 60 | # 1 if daemon was already started 61 | # 2 if daemon could not be started 62 | 63 | # Test if daemon already exist 64 | start-stop-daemon --test --start --quiet --pidfile $PIDFILE \ 65 | --exec $DAEMON > /dev/null \ 66 | || return 1 67 | # Start it if not 68 | start-stop-daemon --start --quiet --pidfile $PIDFILE \ 69 | --exec $DAEMON -- $DAEMON_ARGS \ 70 | || return 2 71 | # Add code here, if the process need to be ready to handle 72 | # request form service that depend on it. At last resort, 73 | # sleep some time. 74 | sleep 1s 75 | } 76 | 77 | # 78 | # Function that stop the dameon 79 | # 80 | do_stop() { 81 | # Return value 82 | # 0 if daemon has been stopped 83 | # 1 if daemon was already stopped 84 | # 2 if daemon could not be stop 85 | # other if a failure occured 86 | ### 87 | # When nsca exits, clean lock file. 88 | start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME 89 | RETVAL="$?" 90 | # If process was already stop. Nothing to do. Exit with 1 91 | [ "$RETVAL" = 1 ] && return 1 92 | # If process could not be stop. Exit with 2 93 | [ "$RETVAL" = 2 ] && return 2 94 | # If the daemon is only run from initscript 95 | # and forks, wait for children to finish. 96 | # If this two condition are not satisfied the add code 97 | # that waits for the process to drop all resources that 98 | # could be needed by services started subsequently. 99 | # At a last resort, sleep for some time. 100 | start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --pidfile $PIDFILE --exec $DAEMON 101 | [ "$?" = 2 ] && return 2 102 | # Many daemon do not delete their pidfiles when they exit 103 | rm -f $PIDFILE 104 | return "$RETVAL" 105 | } 106 | 107 | # 108 | # Function that sends a SIGHUP to the daemon 109 | # 110 | do_reload() 111 | { 112 | # 113 | # A basic reload function. Not used. 114 | start-stop-daemon --stop --quiet --signal 1 --pidfile $PIDFILE --name $NAME 115 | return 0 116 | } 117 | 118 | case "$1" in 119 | start) 120 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" 121 | do_start 122 | case "$?" in 123 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 124 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 125 | *) log_end_msg 1 ;; # Failed to start. Fatal 126 | esac 127 | ;; 128 | stop) 129 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" 130 | do_stop 131 | case "$?" in 132 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 133 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; 134 | *) log_end_msg 1 ;; # Failed to stop. Fatal 135 | esac 136 | ;; 137 | #reload|force-reload) 138 | # # 139 | # # If do_reload() is not implemented then leave this comment out 140 | # # and leave "force-reload" as an alias for "restart". 141 | # # 142 | # log_daemon_msg "Reloading $DESC" "$NAME" 143 | # do_reload 144 | # # Note : the basic do_reload always return 0 145 | # log_end_msg "$?" 146 | # ;; 147 | restart|force-reload) 148 | # 149 | # If the "reload" option is implemented then remove 150 | # the "force-reload" alias. 151 | log_daemon_msg "Restarting $DESC" "$NAME" 152 | do_stop 153 | case "$?" in 154 | 0|1) 155 | do_start 156 | case "$?" in 157 | 0) log_end_msg 0 ;; 158 | 1) log_end_msg 1 ;; # Old process still running 159 | *) log_end_msg 1 ;; # Failed to start 160 | esac 161 | ;; 162 | *) 163 | # Failed to stop 164 | log_end_msg 1 165 | ;; 166 | esac 167 | ;; 168 | status) 169 | log_daemon_msg "Checking status of $DESC" "$NAME" 170 | status_of_proc -p $PIDFILE "$DAEMON" "$NAME" 171 | log_end_msg "$?" 172 | exit $? 173 | ;; 174 | *) 175 | # echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload|status}" >&2 176 | echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload|status}" >&2 177 | exit 3 178 | ;; 179 | esac 180 | 181 | # ":" = "exit 0" 182 | : 183 | -------------------------------------------------------------------------------- /scripts/tuntox.service: -------------------------------------------------------------------------------- 1 | # Systemd service file 2 | 3 | [Unit] 4 | Description=Tuntox - TCP tunnel over Tox protocol 5 | After=network.target 6 | 7 | [Service] 8 | Type=simple 9 | 10 | # Copy the tuntox binary to /usr/bin first 11 | 12 | ExecStart=/usr/bin/tuntox 13 | Restart=on-failure 14 | 15 | # Change this to your user and group for increased security 16 | # Make sure this user/group has access to /etc/tuntox 17 | #User=proxy 18 | #Group=proxy 19 | 20 | # Uncomment this and add a password to enable authentication 21 | #Environment=TUNTOX_SHARED_SECRET=yourpassword 22 | 23 | # Makes / read-only 24 | ProtectSystem=strict 25 | # … except for /etc/tuntox. Modify this if you change the default directory, 26 | # comment it out if you want to generate a new id on each start. 27 | # Remember that /etc/tuntox still needs to be writable by User! 28 | ReadWriteDirectories=/etc/tuntox 29 | 30 | [Install] 31 | WantedBy=multi-user.target 32 | Alias=tuntox.service 33 | -------------------------------------------------------------------------------- /tox_bootstrap.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Generated with generate_tox_bootstrap.py by GDR! 4 | * from https://nodes.tox.chat/json on 2023-09-29 09:55:44.493291 5 | */ 6 | struct bootstrap_node { 7 | char *address; 8 | uint16_t port; 9 | uint8_t key[32]; 10 | } bootstrap_nodes[] = { 11 | 12 | { 13 | "144.217.167.73", 14 | 33445, 15 | { 16 | 0x7E, 0x56, 0x68, 0xE0, 0xEE, 0x09, 0xE1, 0x9F, 0x32, 0x0A, 0xD4, 0x79, 0x02, 0x41, 0x93, 0x31, 17 | 0xFF, 0xEE, 0x14, 0x7B, 0xB3, 0x60, 0x67, 0x69, 0xCF, 0xBE, 0x92, 0x1A, 0x2A, 0x2F, 0xD3, 0x4C 18 | } 19 | }, 20 | 21 | { 22 | "172.103.164.250", 23 | 33445, 24 | { 25 | 0x10, 0xC0, 0x0E, 0xB2, 0x50, 0xC3, 0x23, 0x3E, 0x34, 0x3E, 0x2A, 0xEB, 0xA0, 0x71, 0x15, 0xA5, 26 | 0xC2, 0x89, 0x20, 0xE9, 0xC8, 0xD2, 0x94, 0x92, 0xF6, 0xD0, 0x0B, 0x29, 0x04, 0x9E, 0xDC, 0x7E 27 | } 28 | }, 29 | 30 | { 31 | "82.196.15.215", 32 | 33445, 33 | { 34 | 0x82, 0xEF, 0x82, 0xBA, 0x33, 0x44, 0x5A, 0x1F, 0x91, 0xA7, 0xDB, 0x27, 0x18, 0x9E, 0xCF, 0xC0, 35 | 0xC0, 0x13, 0xE0, 0x6E, 0x3D, 0xA7, 0x1F, 0x58, 0x8E, 0xD6, 0x92, 0xBE, 0xD6, 0x25, 0xEC, 0x23 36 | } 37 | }, 38 | 39 | { 40 | "82.196.15.215", 41 | 33445, 42 | { 43 | 0x82, 0xEF, 0x82, 0xBA, 0x33, 0x44, 0x5A, 0x1F, 0x91, 0xA7, 0xDB, 0x27, 0x18, 0x9E, 0xCF, 0xC0, 44 | 0xC0, 0x13, 0xE0, 0x6E, 0x3D, 0xA7, 0x1F, 0x58, 0x8E, 0xD6, 0x92, 0xBE, 0xD6, 0x25, 0xEC, 0x23 45 | } 46 | }, 47 | 48 | { 49 | "205.185.115.131", 50 | 53, 51 | { 52 | 0x30, 0x91, 0xC6, 0xBE, 0xB2, 0xA9, 0x93, 0xF1, 0xC6, 0x30, 0x0C, 0x16, 0x54, 0x9F, 0xAB, 0xA6, 53 | 0x70, 0x98, 0xFF, 0x3D, 0x62, 0xC6, 0xD2, 0x53, 0x82, 0x8B, 0x53, 0x14, 0x70, 0xB5, 0x3D, 0x68 54 | } 55 | }, 56 | 57 | { 58 | "2a03:b0c0:3:d0::ac:5001", 59 | 33445, 60 | { 61 | 0xCD, 0x13, 0x3B, 0x52, 0x11, 0x59, 0x54, 0x1F, 0xB1, 0xD3, 0x26, 0xDE, 0x98, 0x50, 0xF5, 0xE5, 62 | 0x6A, 0x6C, 0x72, 0x4B, 0x5B, 0x8E, 0x5E, 0xB5, 0xCD, 0x8D, 0x95, 0x04, 0x08, 0xE9, 0x57, 0x07 63 | } 64 | }, 65 | 66 | { 67 | "2a03:b0c0:3:d0::ac:5001", 68 | 33445, 69 | { 70 | 0xCD, 0x13, 0x3B, 0x52, 0x11, 0x59, 0x54, 0x1F, 0xB1, 0xD3, 0x26, 0xDE, 0x98, 0x50, 0xF5, 0xE5, 71 | 0x6A, 0x6C, 0x72, 0x4B, 0x5B, 0x8E, 0x5E, 0xB5, 0xCD, 0x8D, 0x95, 0x04, 0x08, 0xE9, 0x57, 0x07 72 | } 73 | }, 74 | 75 | { 76 | "49.12.229.145", 77 | 33445, 78 | { 79 | 0xB3, 0xE5, 0xFA, 0x80, 0xDC, 0x8E, 0xBD, 0x11, 0x49, 0xAD, 0x2A, 0xB3, 0x5E, 0xD8, 0xB8, 0x5B, 80 | 0xD5, 0x46, 0xDE, 0xDE, 0x26, 0x1C, 0xA5, 0x93, 0x23, 0x4C, 0x61, 0x92, 0x49, 0x41, 0x95, 0x06 81 | } 82 | }, 83 | 84 | { 85 | "49.12.229.145", 86 | 33445, 87 | { 88 | 0xB3, 0xE5, 0xFA, 0x80, 0xDC, 0x8E, 0xBD, 0x11, 0x49, 0xAD, 0x2A, 0xB3, 0x5E, 0xD8, 0xB8, 0x5B, 89 | 0xD5, 0x46, 0xDE, 0xDE, 0x26, 0x1C, 0xA5, 0x93, 0x23, 0x4C, 0x61, 0x92, 0x49, 0x41, 0x95, 0x06 90 | } 91 | }, 92 | 93 | { 94 | "195.201.7.101", 95 | 33445, 96 | { 97 | 0xB8, 0x4E, 0x86, 0x51, 0x25, 0xB4, 0xEC, 0x4C, 0x36, 0x8C, 0xD0, 0x47, 0xC7, 0x2B, 0xCE, 0x44, 98 | 0x76, 0x44, 0xA2, 0xDC, 0x31, 0xEF, 0x75, 0xBD, 0x2C, 0xDA, 0x34, 0x5B, 0xFD, 0x31, 0x01, 0x07 99 | } 100 | }, 101 | 102 | { 103 | "37.221.66.161", 104 | 33445, 105 | { 106 | 0x83, 0x6D, 0x1D, 0xA2, 0xBE, 0x12, 0xFE, 0x0E, 0x66, 0x93, 0x34, 0xE4, 0x37, 0xBE, 0x3F, 0xB0, 107 | 0x28, 0x06, 0xF1, 0x52, 0x8C, 0x2B, 0x27, 0x82, 0x11, 0x3E, 0x09, 0x10, 0xC7, 0x71, 0x14, 0x09 108 | } 109 | }, 110 | 111 | { 112 | "5.19.249.240", 113 | 38296, 114 | { 115 | 0xDA, 0x98, 0xA4, 0xC0, 0xCD, 0x74, 0x73, 0xA1, 0x33, 0xE1, 0x15, 0xFE, 0xA2, 0xEB, 0xDA, 0xEE, 116 | 0xA2, 0xEF, 0x4F, 0x79, 0xFD, 0x69, 0x32, 0x5F, 0xC0, 0x70, 0xDA, 0x4D, 0xE4, 0xBA, 0x32, 0x38 117 | } 118 | }, 119 | 120 | { 121 | "209:dead:ded:4991:49f3:b6c0:9869:3019", 122 | 33445, 123 | { 124 | 0x19, 0x11, 0x34, 0x1A, 0x83, 0xE0, 0x25, 0x03, 0xAB, 0x1F, 0xD6, 0x56, 0x1B, 0xD6, 0x4A, 0xF3, 125 | 0xA9, 0xD6, 0xC3, 0xF1, 0x2B, 0x5F, 0xBB, 0x65, 0x69, 0x76, 0xB2, 0xE6, 0x78, 0x64, 0x4A, 0x67 126 | } 127 | }, 128 | 129 | { 130 | "209:dead:ded:4991:49f3:b6c0:9869:3019", 131 | 33445, 132 | { 133 | 0x19, 0x11, 0x34, 0x1A, 0x83, 0xE0, 0x25, 0x03, 0xAB, 0x1F, 0xD6, 0x56, 0x1B, 0xD6, 0x4A, 0xF3, 134 | 0xA9, 0xD6, 0xC3, 0xF1, 0x2B, 0x5F, 0xBB, 0x65, 0x69, 0x76, 0xB2, 0xE6, 0x78, 0x64, 0x4A, 0x67 135 | } 136 | }, 137 | 138 | { 139 | "87.203.194.6", 140 | 33445, 141 | { 142 | 0x4B, 0x03, 0x1C, 0x96, 0x67, 0x3B, 0x6F, 0xF1, 0x23, 0x26, 0x9F, 0xF1, 0x8F, 0x28, 0x47, 0xE1, 143 | 0x90, 0x9A, 0x8A, 0x04, 0x64, 0x2B, 0xBE, 0xCD, 0x01, 0x89, 0xAC, 0x8A, 0xEE, 0xAD, 0xAF, 0x64 144 | } 145 | }, 146 | 147 | { 148 | "87.203.194.6", 149 | 33445, 150 | { 151 | 0x4B, 0x03, 0x1C, 0x96, 0x67, 0x3B, 0x6F, 0xF1, 0x23, 0x26, 0x9F, 0xF1, 0x8F, 0x28, 0x47, 0xE1, 152 | 0x90, 0x9A, 0x8A, 0x04, 0x64, 0x2B, 0xBE, 0xCD, 0x01, 0x89, 0xAC, 0x8A, 0xEE, 0xAD, 0xAF, 0x64 153 | } 154 | }, 155 | 156 | { 157 | "104.225.141.59", 158 | 43334, 159 | { 160 | 0x93, 0x3B, 0xA2, 0x0B, 0x2E, 0x25, 0x8B, 0x4C, 0x0D, 0x47, 0x5B, 0x6D, 0xEC, 0xE9, 0x0C, 0x7E, 161 | 0x82, 0x7F, 0xE8, 0x3E, 0xFA, 0x96, 0x55, 0x41, 0x4E, 0x78, 0x41, 0x25, 0x1B, 0x19, 0xA7, 0x2C 162 | } 163 | }, 164 | 165 | { 166 | "2400:8902::f03c:93ff:fe69:bf77", 167 | 33445, 168 | { 169 | 0xF7, 0x6A, 0x11, 0x28, 0x45, 0x47, 0x16, 0x38, 0x89, 0xDD, 0xC8, 0x9A, 0x77, 0x38, 0xCF, 0x27, 170 | 0x17, 0x97, 0xBF, 0x5E, 0x5E, 0x22, 0x06, 0x43, 0xE9, 0x7A, 0xD3, 0xC7, 0xE7, 0x90, 0x3D, 0x55 171 | } 172 | }, 173 | 174 | { 175 | "2400:8902::f03c:93ff:fe69:bf77", 176 | 33445, 177 | { 178 | 0xF7, 0x6A, 0x11, 0x28, 0x45, 0x47, 0x16, 0x38, 0x89, 0xDD, 0xC8, 0x9A, 0x77, 0x38, 0xCF, 0x27, 179 | 0x17, 0x97, 0xBF, 0x5E, 0x5E, 0x22, 0x06, 0x43, 0xE9, 0x7A, 0xD3, 0xC7, 0xE7, 0x90, 0x3D, 0x55 180 | } 181 | }, 182 | 183 | { 184 | "2600:3c04::f03c:92ff:fe30:5df", 185 | 33445, 186 | { 187 | 0xD4, 0x6E, 0x97, 0xCF, 0x99, 0x5D, 0xC1, 0x82, 0x0B, 0x92, 0xB7, 0xD8, 0x99, 0xE1, 0x52, 0xA2, 188 | 0x17, 0xD3, 0x6A, 0xBE, 0x22, 0x73, 0x0F, 0xEA, 0x4B, 0x6B, 0xF1, 0xBF, 0xC0, 0x6C, 0x61, 0x7C 189 | } 190 | }, 191 | 192 | { 193 | "2600:3c04::f03c:92ff:fe30:5df", 194 | 33445, 195 | { 196 | 0xD4, 0x6E, 0x97, 0xCF, 0x99, 0x5D, 0xC1, 0x82, 0x0B, 0x92, 0xB7, 0xD8, 0x99, 0xE1, 0x52, 0xA2, 197 | 0x17, 0xD3, 0x6A, 0xBE, 0x22, 0x73, 0x0F, 0xEA, 0x4B, 0x6B, 0xF1, 0xBF, 0xC0, 0x6C, 0x61, 0x7C 198 | } 199 | }, 200 | 201 | { 202 | "91.146.66.26", 203 | 33445, 204 | { 205 | 0xB5, 0xE7, 0xDA, 0xC6, 0x10, 0xDB, 0xDE, 0x55, 0xF3, 0x59, 0xC7, 0xF8, 0x69, 0x0B, 0x29, 0x4C, 206 | 0x8E, 0x4F, 0xCE, 0xC4, 0x38, 0x5D, 0xE9, 0x52, 0x5D, 0xBF, 0xA5, 0x52, 0x3E, 0xAD, 0x9D, 0x53 207 | } 208 | }, 209 | 210 | { 211 | "168.119.209.10", 212 | 33445, 213 | { 214 | 0xB6, 0x62, 0x6D, 0x38, 0x6B, 0xE7, 0xE3, 0xAC, 0xA1, 0x07, 0xB4, 0x6F, 0x48, 0xA5, 0xC4, 0xD5, 215 | 0x22, 0xD2, 0x92, 0x81, 0x75, 0x0D, 0x44, 0xA0, 0xCB, 0xA6, 0xA2, 0x72, 0x1E, 0x79, 0xC9, 0x51 216 | } 217 | }, 218 | 219 | { 220 | "168.119.209.10", 221 | 33445, 222 | { 223 | 0xB6, 0x62, 0x6D, 0x38, 0x6B, 0xE7, 0xE3, 0xAC, 0xA1, 0x07, 0xB4, 0x6F, 0x48, 0xA5, 0xC4, 0xD5, 224 | 0x22, 0xD2, 0x92, 0x81, 0x75, 0x0D, 0x44, 0xA0, 0xCB, 0xA6, 0xA2, 0x72, 0x1E, 0x79, 0xC9, 0x51 225 | } 226 | }, 227 | 228 | { 229 | "51.15.227.109", 230 | 33445, 231 | { 232 | 0xD3, 0xD6, 0xD7, 0xC0, 0xC7, 0x00, 0x9F, 0xC7, 0x54, 0x06, 0xB0, 0xA4, 0x9E, 0x47, 0x59, 0x96, 233 | 0xC8, 0xC4, 0xF8, 0xBC, 0xE1, 0xE6, 0xFC, 0x59, 0x67, 0xDE, 0x42, 0x7F, 0x8F, 0x60, 0x05, 0x27 234 | } 235 | }, 236 | 237 | { 238 | "51.15.227.109", 239 | 33445, 240 | { 241 | 0xD3, 0xD6, 0xD7, 0xC0, 0xC7, 0x00, 0x9F, 0xC7, 0x54, 0x06, 0xB0, 0xA4, 0x9E, 0x47, 0x59, 0x96, 242 | 0xC8, 0xC4, 0xF8, 0xBC, 0xE1, 0xE6, 0xFC, 0x59, 0x67, 0xDE, 0x42, 0x7F, 0x8F, 0x60, 0x05, 0x27 243 | } 244 | }, 245 | 246 | { 247 | "137.220.55.93", 248 | 33445, 249 | { 250 | 0xBE, 0x7E, 0xD5, 0x3C, 0xD9, 0x24, 0x81, 0x35, 0x07, 0xBA, 0x71, 0x1F, 0xD4, 0x03, 0x86, 0x06, 251 | 0x2E, 0x6D, 0xC6, 0xF7, 0x90, 0xEF, 0xA1, 0x22, 0xC7, 0x8F, 0x7C, 0xDE, 0xEE, 0x4B, 0x6D, 0x1B 252 | } 253 | }, 254 | 255 | { 256 | "137.220.55.93", 257 | 33445, 258 | { 259 | 0xBE, 0x7E, 0xD5, 0x3C, 0xD9, 0x24, 0x81, 0x35, 0x07, 0xBA, 0x71, 0x1F, 0xD4, 0x03, 0x86, 0x06, 260 | 0x2E, 0x6D, 0xC6, 0xF7, 0x90, 0xEF, 0xA1, 0x22, 0xC7, 0x8F, 0x7C, 0xDE, 0xEE, 0x4B, 0x6D, 0x1B 261 | } 262 | }, 263 | 264 | { 265 | "2600:3c03::f03c:93ff:fe7f:6096", 266 | 33445, 267 | { 268 | 0xDA, 0x2B, 0xD9, 0x27, 0xE0, 0x1C, 0xD0, 0x5E, 0xBC, 0xC2, 0x57, 0x4E, 0xBE, 0x5B, 0xEB, 0xB1, 269 | 0x0F, 0xF5, 0x9A, 0xE0, 0xB2, 0x10, 0x5A, 0x7D, 0x1E, 0x2B, 0x40, 0xE4, 0x9B, 0xB2, 0x02, 0x39 270 | } 271 | }, 272 | 273 | { 274 | "2600:3c03::f03c:93ff:fe7f:6096", 275 | 33445, 276 | { 277 | 0xDA, 0x2B, 0xD9, 0x27, 0xE0, 0x1C, 0xD0, 0x5E, 0xBC, 0xC2, 0x57, 0x4E, 0xBE, 0x5B, 0xEB, 0xB1, 278 | 0x0F, 0xF5, 0x9A, 0xE0, 0xB2, 0x10, 0x5A, 0x7D, 0x1E, 0x2B, 0x40, 0xE4, 0x9B, 0xB2, 0x02, 0x39 279 | } 280 | }, 281 | 282 | { 283 | "114.35.245.150", 284 | 33445, 285 | { 286 | 0x3F, 0x0A, 0x45, 0xA2, 0x68, 0x36, 0x7C, 0x1B, 0xEA, 0x65, 0x2F, 0x25, 0x8C, 0x85, 0xF4, 0xA6, 287 | 0x6D, 0xA7, 0x6B, 0xCA, 0xA6, 0x67, 0xA4, 0x9E, 0x77, 0x0B, 0xCC, 0x49, 0x17, 0xAB, 0x6A, 0x25 288 | } 289 | }, 290 | 291 | { 292 | "114.35.245.150", 293 | 33445, 294 | { 295 | 0x3F, 0x0A, 0x45, 0xA2, 0x68, 0x36, 0x7C, 0x1B, 0xEA, 0x65, 0x2F, 0x25, 0x8C, 0x85, 0xF4, 0xA6, 296 | 0x6D, 0xA7, 0x6B, 0xCA, 0xA6, 0x67, 0xA4, 0x9E, 0x77, 0x0B, 0xCC, 0x49, 0x17, 0xAB, 0x6A, 0x25 297 | } 298 | }, 299 | 300 | { 301 | "104.244.74.69", 302 | 33445, 303 | { 304 | 0x8E, 0x8B, 0x63, 0x29, 0x9B, 0x3D, 0x52, 0x0F, 0xB3, 0x77, 0xFE, 0x51, 0x00, 0xE6, 0x5E, 0x33, 305 | 0x22, 0xF7, 0xAE, 0x5B, 0x20, 0xA0, 0xAC, 0xED, 0x29, 0x81, 0x76, 0x9F, 0xC5, 0xB4, 0x37, 0x25 306 | } 307 | }, 308 | 309 | { 310 | "104.244.74.69", 311 | 33445, 312 | { 313 | 0x8E, 0x8B, 0x63, 0x29, 0x9B, 0x3D, 0x52, 0x0F, 0xB3, 0x77, 0xFE, 0x51, 0x00, 0xE6, 0x5E, 0x33, 314 | 0x22, 0xF7, 0xAE, 0x5B, 0x20, 0xA0, 0xAC, 0xED, 0x29, 0x81, 0x76, 0x9F, 0xC5, 0xB4, 0x37, 0x25 315 | } 316 | }, 317 | 318 | { 319 | "188.214.122.30", 320 | 33445, 321 | { 322 | 0x2A, 0x9F, 0x7A, 0x62, 0x05, 0x81, 0xD5, 0xD1, 0xB0, 0x9B, 0x00, 0x46, 0x24, 0x55, 0x92, 0x11, 323 | 0xC5, 0xED, 0x3D, 0x1D, 0x71, 0x2E, 0x80, 0x66, 0xAC, 0xDB, 0x08, 0x96, 0xA7, 0x33, 0x57, 0x05 324 | } 325 | }, 326 | 327 | }; 328 | 329 | struct bootstrap_node tcp_relays[] = { 330 | 331 | { 332 | "144.217.167.73", 333 | 3389, 334 | { 335 | 0x7E, 0x56, 0x68, 0xE0, 0xEE, 0x09, 0xE1, 0x9F, 0x32, 0x0A, 0xD4, 0x79, 0x02, 0x41, 0x93, 0x31, 336 | 0xFF, 0xEE, 0x14, 0x7B, 0xB3, 0x60, 0x67, 0x69, 0xCF, 0xBE, 0x92, 0x1A, 0x2A, 0x2F, 0xD3, 0x4C 337 | } 338 | }, 339 | 340 | { 341 | "144.217.167.73", 342 | 33445, 343 | { 344 | 0x7E, 0x56, 0x68, 0xE0, 0xEE, 0x09, 0xE1, 0x9F, 0x32, 0x0A, 0xD4, 0x79, 0x02, 0x41, 0x93, 0x31, 345 | 0xFF, 0xEE, 0x14, 0x7B, 0xB3, 0x60, 0x67, 0x69, 0xCF, 0xBE, 0x92, 0x1A, 0x2A, 0x2F, 0xD3, 0x4C 346 | } 347 | }, 348 | 349 | { 350 | "172.103.164.250", 351 | 33445, 352 | { 353 | 0x10, 0xC0, 0x0E, 0xB2, 0x50, 0xC3, 0x23, 0x3E, 0x34, 0x3E, 0x2A, 0xEB, 0xA0, 0x71, 0x15, 0xA5, 354 | 0xC2, 0x89, 0x20, 0xE9, 0xC8, 0xD2, 0x94, 0x92, 0xF6, 0xD0, 0x0B, 0x29, 0x04, 0x9E, 0xDC, 0x7E 355 | } 356 | }, 357 | 358 | { 359 | "205.185.115.131", 360 | 33445, 361 | { 362 | 0x30, 0x91, 0xC6, 0xBE, 0xB2, 0xA9, 0x93, 0xF1, 0xC6, 0x30, 0x0C, 0x16, 0x54, 0x9F, 0xAB, 0xA6, 363 | 0x70, 0x98, 0xFF, 0x3D, 0x62, 0xC6, 0xD2, 0x53, 0x82, 0x8B, 0x53, 0x14, 0x70, 0xB5, 0x3D, 0x68 364 | } 365 | }, 366 | 367 | { 368 | "205.185.115.131", 369 | 53, 370 | { 371 | 0x30, 0x91, 0xC6, 0xBE, 0xB2, 0xA9, 0x93, 0xF1, 0xC6, 0x30, 0x0C, 0x16, 0x54, 0x9F, 0xAB, 0xA6, 372 | 0x70, 0x98, 0xFF, 0x3D, 0x62, 0xC6, 0xD2, 0x53, 0x82, 0x8B, 0x53, 0x14, 0x70, 0xB5, 0x3D, 0x68 373 | } 374 | }, 375 | 376 | { 377 | "205.185.115.131", 378 | 443, 379 | { 380 | 0x30, 0x91, 0xC6, 0xBE, 0xB2, 0xA9, 0x93, 0xF1, 0xC6, 0x30, 0x0C, 0x16, 0x54, 0x9F, 0xAB, 0xA6, 381 | 0x70, 0x98, 0xFF, 0x3D, 0x62, 0xC6, 0xD2, 0x53, 0x82, 0x8B, 0x53, 0x14, 0x70, 0xB5, 0x3D, 0x68 382 | } 383 | }, 384 | 385 | { 386 | "205.185.115.131", 387 | 3389, 388 | { 389 | 0x30, 0x91, 0xC6, 0xBE, 0xB2, 0xA9, 0x93, 0xF1, 0xC6, 0x30, 0x0C, 0x16, 0x54, 0x9F, 0xAB, 0xA6, 390 | 0x70, 0x98, 0xFF, 0x3D, 0x62, 0xC6, 0xD2, 0x53, 0x82, 0x8B, 0x53, 0x14, 0x70, 0xB5, 0x3D, 0x68 391 | } 392 | }, 393 | 394 | { 395 | "46.101.197.175", 396 | 33445, 397 | { 398 | 0xCD, 0x13, 0x3B, 0x52, 0x11, 0x59, 0x54, 0x1F, 0xB1, 0xD3, 0x26, 0xDE, 0x98, 0x50, 0xF5, 0xE5, 399 | 0x6A, 0x6C, 0x72, 0x4B, 0x5B, 0x8E, 0x5E, 0xB5, 0xCD, 0x8D, 0x95, 0x04, 0x08, 0xE9, 0x57, 0x07 400 | } 401 | }, 402 | 403 | { 404 | "46.101.197.175", 405 | 3389, 406 | { 407 | 0xCD, 0x13, 0x3B, 0x52, 0x11, 0x59, 0x54, 0x1F, 0xB1, 0xD3, 0x26, 0xDE, 0x98, 0x50, 0xF5, 0xE5, 408 | 0x6A, 0x6C, 0x72, 0x4B, 0x5B, 0x8E, 0x5E, 0xB5, 0xCD, 0x8D, 0x95, 0x04, 0x08, 0xE9, 0x57, 0x07 409 | } 410 | }, 411 | 412 | { 413 | "2a03:b0c0:3:d0::ac:5001", 414 | 33445, 415 | { 416 | 0xCD, 0x13, 0x3B, 0x52, 0x11, 0x59, 0x54, 0x1F, 0xB1, 0xD3, 0x26, 0xDE, 0x98, 0x50, 0xF5, 0xE5, 417 | 0x6A, 0x6C, 0x72, 0x4B, 0x5B, 0x8E, 0x5E, 0xB5, 0xCD, 0x8D, 0x95, 0x04, 0x08, 0xE9, 0x57, 0x07 418 | } 419 | }, 420 | 421 | { 422 | "2a03:b0c0:3:d0::ac:5001", 423 | 3389, 424 | { 425 | 0xCD, 0x13, 0x3B, 0x52, 0x11, 0x59, 0x54, 0x1F, 0xB1, 0xD3, 0x26, 0xDE, 0x98, 0x50, 0xF5, 0xE5, 426 | 0x6A, 0x6C, 0x72, 0x4B, 0x5B, 0x8E, 0x5E, 0xB5, 0xCD, 0x8D, 0x95, 0x04, 0x08, 0xE9, 0x57, 0x07 427 | } 428 | }, 429 | 430 | { 431 | "49.12.229.145", 432 | 33445, 433 | { 434 | 0xB3, 0xE5, 0xFA, 0x80, 0xDC, 0x8E, 0xBD, 0x11, 0x49, 0xAD, 0x2A, 0xB3, 0x5E, 0xD8, 0xB8, 0x5B, 435 | 0xD5, 0x46, 0xDE, 0xDE, 0x26, 0x1C, 0xA5, 0x93, 0x23, 0x4C, 0x61, 0x92, 0x49, 0x41, 0x95, 0x06 436 | } 437 | }, 438 | 439 | { 440 | "49.12.229.145", 441 | 3389, 442 | { 443 | 0xB3, 0xE5, 0xFA, 0x80, 0xDC, 0x8E, 0xBD, 0x11, 0x49, 0xAD, 0x2A, 0xB3, 0x5E, 0xD8, 0xB8, 0x5B, 444 | 0xD5, 0x46, 0xDE, 0xDE, 0x26, 0x1C, 0xA5, 0x93, 0x23, 0x4C, 0x61, 0x92, 0x49, 0x41, 0x95, 0x06 445 | } 446 | }, 447 | 448 | { 449 | "49.12.229.145", 450 | 33445, 451 | { 452 | 0xB3, 0xE5, 0xFA, 0x80, 0xDC, 0x8E, 0xBD, 0x11, 0x49, 0xAD, 0x2A, 0xB3, 0x5E, 0xD8, 0xB8, 0x5B, 453 | 0xD5, 0x46, 0xDE, 0xDE, 0x26, 0x1C, 0xA5, 0x93, 0x23, 0x4C, 0x61, 0x92, 0x49, 0x41, 0x95, 0x06 454 | } 455 | }, 456 | 457 | { 458 | "49.12.229.145", 459 | 3389, 460 | { 461 | 0xB3, 0xE5, 0xFA, 0x80, 0xDC, 0x8E, 0xBD, 0x11, 0x49, 0xAD, 0x2A, 0xB3, 0x5E, 0xD8, 0xB8, 0x5B, 462 | 0xD5, 0x46, 0xDE, 0xDE, 0x26, 0x1C, 0xA5, 0x93, 0x23, 0x4C, 0x61, 0x92, 0x49, 0x41, 0x95, 0x06 463 | } 464 | }, 465 | 466 | { 467 | "195.201.7.101", 468 | 3389, 469 | { 470 | 0xB8, 0x4E, 0x86, 0x51, 0x25, 0xB4, 0xEC, 0x4C, 0x36, 0x8C, 0xD0, 0x47, 0xC7, 0x2B, 0xCE, 0x44, 471 | 0x76, 0x44, 0xA2, 0xDC, 0x31, 0xEF, 0x75, 0xBD, 0x2C, 0xDA, 0x34, 0x5B, 0xFD, 0x31, 0x01, 0x07 472 | } 473 | }, 474 | 475 | { 476 | "195.201.7.101", 477 | 33445, 478 | { 479 | 0xB8, 0x4E, 0x86, 0x51, 0x25, 0xB4, 0xEC, 0x4C, 0x36, 0x8C, 0xD0, 0x47, 0xC7, 0x2B, 0xCE, 0x44, 480 | 0x76, 0x44, 0xA2, 0xDC, 0x31, 0xEF, 0x75, 0xBD, 0x2C, 0xDA, 0x34, 0x5B, 0xFD, 0x31, 0x01, 0x07 481 | } 482 | }, 483 | 484 | { 485 | "37.221.66.161", 486 | 443, 487 | { 488 | 0x83, 0x6D, 0x1D, 0xA2, 0xBE, 0x12, 0xFE, 0x0E, 0x66, 0x93, 0x34, 0xE4, 0x37, 0xBE, 0x3F, 0xB0, 489 | 0x28, 0x06, 0xF1, 0x52, 0x8C, 0x2B, 0x27, 0x82, 0x11, 0x3E, 0x09, 0x10, 0xC7, 0x71, 0x14, 0x09 490 | } 491 | }, 492 | 493 | { 494 | "37.221.66.161", 495 | 3389, 496 | { 497 | 0x83, 0x6D, 0x1D, 0xA2, 0xBE, 0x12, 0xFE, 0x0E, 0x66, 0x93, 0x34, 0xE4, 0x37, 0xBE, 0x3F, 0xB0, 498 | 0x28, 0x06, 0xF1, 0x52, 0x8C, 0x2B, 0x27, 0x82, 0x11, 0x3E, 0x09, 0x10, 0xC7, 0x71, 0x14, 0x09 499 | } 500 | }, 501 | 502 | { 503 | "37.221.66.161", 504 | 33445, 505 | { 506 | 0x83, 0x6D, 0x1D, 0xA2, 0xBE, 0x12, 0xFE, 0x0E, 0x66, 0x93, 0x34, 0xE4, 0x37, 0xBE, 0x3F, 0xB0, 507 | 0x28, 0x06, 0xF1, 0x52, 0x8C, 0x2B, 0x27, 0x82, 0x11, 0x3E, 0x09, 0x10, 0xC7, 0x71, 0x14, 0x09 508 | } 509 | }, 510 | 511 | { 512 | "5.19.249.240", 513 | 3389, 514 | { 515 | 0xDA, 0x98, 0xA4, 0xC0, 0xCD, 0x74, 0x73, 0xA1, 0x33, 0xE1, 0x15, 0xFE, 0xA2, 0xEB, 0xDA, 0xEE, 516 | 0xA2, 0xEF, 0x4F, 0x79, 0xFD, 0x69, 0x32, 0x5F, 0xC0, 0x70, 0xDA, 0x4D, 0xE4, 0xBA, 0x32, 0x38 517 | } 518 | }, 519 | 520 | { 521 | "5.19.249.240", 522 | 38296, 523 | { 524 | 0xDA, 0x98, 0xA4, 0xC0, 0xCD, 0x74, 0x73, 0xA1, 0x33, 0xE1, 0x15, 0xFE, 0xA2, 0xEB, 0xDA, 0xEE, 525 | 0xA2, 0xEF, 0x4F, 0x79, 0xFD, 0x69, 0x32, 0x5F, 0xC0, 0x70, 0xDA, 0x4D, 0xE4, 0xBA, 0x32, 0x38 526 | } 527 | }, 528 | 529 | { 530 | "188.225.9.167", 531 | 33445, 532 | { 533 | 0x19, 0x11, 0x34, 0x1A, 0x83, 0xE0, 0x25, 0x03, 0xAB, 0x1F, 0xD6, 0x56, 0x1B, 0xD6, 0x4A, 0xF3, 534 | 0xA9, 0xD6, 0xC3, 0xF1, 0x2B, 0x5F, 0xBB, 0x65, 0x69, 0x76, 0xB2, 0xE6, 0x78, 0x64, 0x4A, 0x67 535 | } 536 | }, 537 | 538 | { 539 | "188.225.9.167", 540 | 3389, 541 | { 542 | 0x19, 0x11, 0x34, 0x1A, 0x83, 0xE0, 0x25, 0x03, 0xAB, 0x1F, 0xD6, 0x56, 0x1B, 0xD6, 0x4A, 0xF3, 543 | 0xA9, 0xD6, 0xC3, 0xF1, 0x2B, 0x5F, 0xBB, 0x65, 0x69, 0x76, 0xB2, 0xE6, 0x78, 0x64, 0x4A, 0x67 544 | } 545 | }, 546 | 547 | { 548 | "209:dead:ded:4991:49f3:b6c0:9869:3019", 549 | 33445, 550 | { 551 | 0x19, 0x11, 0x34, 0x1A, 0x83, 0xE0, 0x25, 0x03, 0xAB, 0x1F, 0xD6, 0x56, 0x1B, 0xD6, 0x4A, 0xF3, 552 | 0xA9, 0xD6, 0xC3, 0xF1, 0x2B, 0x5F, 0xBB, 0x65, 0x69, 0x76, 0xB2, 0xE6, 0x78, 0x64, 0x4A, 0x67 553 | } 554 | }, 555 | 556 | { 557 | "209:dead:ded:4991:49f3:b6c0:9869:3019", 558 | 3389, 559 | { 560 | 0x19, 0x11, 0x34, 0x1A, 0x83, 0xE0, 0x25, 0x03, 0xAB, 0x1F, 0xD6, 0x56, 0x1B, 0xD6, 0x4A, 0xF3, 561 | 0xA9, 0xD6, 0xC3, 0xF1, 0x2B, 0x5F, 0xBB, 0x65, 0x69, 0x76, 0xB2, 0xE6, 0x78, 0x64, 0x4A, 0x67 562 | } 563 | }, 564 | 565 | { 566 | "87.203.194.6", 567 | 33445, 568 | { 569 | 0x4B, 0x03, 0x1C, 0x96, 0x67, 0x3B, 0x6F, 0xF1, 0x23, 0x26, 0x9F, 0xF1, 0x8F, 0x28, 0x47, 0xE1, 570 | 0x90, 0x9A, 0x8A, 0x04, 0x64, 0x2B, 0xBE, 0xCD, 0x01, 0x89, 0xAC, 0x8A, 0xEE, 0xAD, 0xAF, 0x64 571 | } 572 | }, 573 | 574 | { 575 | "87.203.194.6", 576 | 33445, 577 | { 578 | 0x4B, 0x03, 0x1C, 0x96, 0x67, 0x3B, 0x6F, 0xF1, 0x23, 0x26, 0x9F, 0xF1, 0x8F, 0x28, 0x47, 0xE1, 579 | 0x90, 0x9A, 0x8A, 0x04, 0x64, 0x2B, 0xBE, 0xCD, 0x01, 0x89, 0xAC, 0x8A, 0xEE, 0xAD, 0xAF, 0x64 580 | } 581 | }, 582 | 583 | { 584 | "104.225.141.59", 585 | 3389, 586 | { 587 | 0x93, 0x3B, 0xA2, 0x0B, 0x2E, 0x25, 0x8B, 0x4C, 0x0D, 0x47, 0x5B, 0x6D, 0xEC, 0xE9, 0x0C, 0x7E, 588 | 0x82, 0x7F, 0xE8, 0x3E, 0xFA, 0x96, 0x55, 0x41, 0x4E, 0x78, 0x41, 0x25, 0x1B, 0x19, 0xA7, 0x2C 589 | } 590 | }, 591 | 592 | { 593 | "104.225.141.59", 594 | 33445, 595 | { 596 | 0x93, 0x3B, 0xA2, 0x0B, 0x2E, 0x25, 0x8B, 0x4C, 0x0D, 0x47, 0x5B, 0x6D, 0xEC, 0xE9, 0x0C, 0x7E, 597 | 0x82, 0x7F, 0xE8, 0x3E, 0xFA, 0x96, 0x55, 0x41, 0x4E, 0x78, 0x41, 0x25, 0x1B, 0x19, 0xA7, 0x2C 598 | } 599 | }, 600 | 601 | { 602 | "139.162.110.188", 603 | 3389, 604 | { 605 | 0xF7, 0x6A, 0x11, 0x28, 0x45, 0x47, 0x16, 0x38, 0x89, 0xDD, 0xC8, 0x9A, 0x77, 0x38, 0xCF, 0x27, 606 | 0x17, 0x97, 0xBF, 0x5E, 0x5E, 0x22, 0x06, 0x43, 0xE9, 0x7A, 0xD3, 0xC7, 0xE7, 0x90, 0x3D, 0x55 607 | } 608 | }, 609 | 610 | { 611 | "139.162.110.188", 612 | 443, 613 | { 614 | 0xF7, 0x6A, 0x11, 0x28, 0x45, 0x47, 0x16, 0x38, 0x89, 0xDD, 0xC8, 0x9A, 0x77, 0x38, 0xCF, 0x27, 615 | 0x17, 0x97, 0xBF, 0x5E, 0x5E, 0x22, 0x06, 0x43, 0xE9, 0x7A, 0xD3, 0xC7, 0xE7, 0x90, 0x3D, 0x55 616 | } 617 | }, 618 | 619 | { 620 | "139.162.110.188", 621 | 33445, 622 | { 623 | 0xF7, 0x6A, 0x11, 0x28, 0x45, 0x47, 0x16, 0x38, 0x89, 0xDD, 0xC8, 0x9A, 0x77, 0x38, 0xCF, 0x27, 624 | 0x17, 0x97, 0xBF, 0x5E, 0x5E, 0x22, 0x06, 0x43, 0xE9, 0x7A, 0xD3, 0xC7, 0xE7, 0x90, 0x3D, 0x55 625 | } 626 | }, 627 | 628 | { 629 | "2400:8902::f03c:93ff:fe69:bf77", 630 | 3389, 631 | { 632 | 0xF7, 0x6A, 0x11, 0x28, 0x45, 0x47, 0x16, 0x38, 0x89, 0xDD, 0xC8, 0x9A, 0x77, 0x38, 0xCF, 0x27, 633 | 0x17, 0x97, 0xBF, 0x5E, 0x5E, 0x22, 0x06, 0x43, 0xE9, 0x7A, 0xD3, 0xC7, 0xE7, 0x90, 0x3D, 0x55 634 | } 635 | }, 636 | 637 | { 638 | "2400:8902::f03c:93ff:fe69:bf77", 639 | 443, 640 | { 641 | 0xF7, 0x6A, 0x11, 0x28, 0x45, 0x47, 0x16, 0x38, 0x89, 0xDD, 0xC8, 0x9A, 0x77, 0x38, 0xCF, 0x27, 642 | 0x17, 0x97, 0xBF, 0x5E, 0x5E, 0x22, 0x06, 0x43, 0xE9, 0x7A, 0xD3, 0xC7, 0xE7, 0x90, 0x3D, 0x55 643 | } 644 | }, 645 | 646 | { 647 | "2400:8902::f03c:93ff:fe69:bf77", 648 | 33445, 649 | { 650 | 0xF7, 0x6A, 0x11, 0x28, 0x45, 0x47, 0x16, 0x38, 0x89, 0xDD, 0xC8, 0x9A, 0x77, 0x38, 0xCF, 0x27, 651 | 0x17, 0x97, 0xBF, 0x5E, 0x5E, 0x22, 0x06, 0x43, 0xE9, 0x7A, 0xD3, 0xC7, 0xE7, 0x90, 0x3D, 0x55 652 | } 653 | }, 654 | 655 | { 656 | "172.105.109.31", 657 | 33445, 658 | { 659 | 0xD4, 0x6E, 0x97, 0xCF, 0x99, 0x5D, 0xC1, 0x82, 0x0B, 0x92, 0xB7, 0xD8, 0x99, 0xE1, 0x52, 0xA2, 660 | 0x17, 0xD3, 0x6A, 0xBE, 0x22, 0x73, 0x0F, 0xEA, 0x4B, 0x6B, 0xF1, 0xBF, 0xC0, 0x6C, 0x61, 0x7C 661 | } 662 | }, 663 | 664 | { 665 | "2600:3c04::f03c:92ff:fe30:5df", 666 | 33445, 667 | { 668 | 0xD4, 0x6E, 0x97, 0xCF, 0x99, 0x5D, 0xC1, 0x82, 0x0B, 0x92, 0xB7, 0xD8, 0x99, 0xE1, 0x52, 0xA2, 669 | 0x17, 0xD3, 0x6A, 0xBE, 0x22, 0x73, 0x0F, 0xEA, 0x4B, 0x6B, 0xF1, 0xBF, 0xC0, 0x6C, 0x61, 0x7C 670 | } 671 | }, 672 | 673 | { 674 | "168.119.209.10", 675 | 33445, 676 | { 677 | 0xB6, 0x62, 0x6D, 0x38, 0x6B, 0xE7, 0xE3, 0xAC, 0xA1, 0x07, 0xB4, 0x6F, 0x48, 0xA5, 0xC4, 0xD5, 678 | 0x22, 0xD2, 0x92, 0x81, 0x75, 0x0D, 0x44, 0xA0, 0xCB, 0xA6, 0xA2, 0x72, 0x1E, 0x79, 0xC9, 0x51 679 | } 680 | }, 681 | 682 | { 683 | "168.119.209.10", 684 | 3389, 685 | { 686 | 0xB6, 0x62, 0x6D, 0x38, 0x6B, 0xE7, 0xE3, 0xAC, 0xA1, 0x07, 0xB4, 0x6F, 0x48, 0xA5, 0xC4, 0xD5, 687 | 0x22, 0xD2, 0x92, 0x81, 0x75, 0x0D, 0x44, 0xA0, 0xCB, 0xA6, 0xA2, 0x72, 0x1E, 0x79, 0xC9, 0x51 688 | } 689 | }, 690 | 691 | { 692 | "168.119.209.10", 693 | 33445, 694 | { 695 | 0xB6, 0x62, 0x6D, 0x38, 0x6B, 0xE7, 0xE3, 0xAC, 0xA1, 0x07, 0xB4, 0x6F, 0x48, 0xA5, 0xC4, 0xD5, 696 | 0x22, 0xD2, 0x92, 0x81, 0x75, 0x0D, 0x44, 0xA0, 0xCB, 0xA6, 0xA2, 0x72, 0x1E, 0x79, 0xC9, 0x51 697 | } 698 | }, 699 | 700 | { 701 | "168.119.209.10", 702 | 3389, 703 | { 704 | 0xB6, 0x62, 0x6D, 0x38, 0x6B, 0xE7, 0xE3, 0xAC, 0xA1, 0x07, 0xB4, 0x6F, 0x48, 0xA5, 0xC4, 0xD5, 705 | 0x22, 0xD2, 0x92, 0x81, 0x75, 0x0D, 0x44, 0xA0, 0xCB, 0xA6, 0xA2, 0x72, 0x1E, 0x79, 0xC9, 0x51 706 | } 707 | }, 708 | 709 | { 710 | "51.15.227.109", 711 | 33445, 712 | { 713 | 0xD3, 0xD6, 0xD7, 0xC0, 0xC7, 0x00, 0x9F, 0xC7, 0x54, 0x06, 0xB0, 0xA4, 0x9E, 0x47, 0x59, 0x96, 714 | 0xC8, 0xC4, 0xF8, 0xBC, 0xE1, 0xE6, 0xFC, 0x59, 0x67, 0xDE, 0x42, 0x7F, 0x8F, 0x60, 0x05, 0x27 715 | } 716 | }, 717 | 718 | { 719 | "51.15.227.109", 720 | 33445, 721 | { 722 | 0xD3, 0xD6, 0xD7, 0xC0, 0xC7, 0x00, 0x9F, 0xC7, 0x54, 0x06, 0xB0, 0xA4, 0x9E, 0x47, 0x59, 0x96, 723 | 0xC8, 0xC4, 0xF8, 0xBC, 0xE1, 0xE6, 0xFC, 0x59, 0x67, 0xDE, 0x42, 0x7F, 0x8F, 0x60, 0x05, 0x27 724 | } 725 | }, 726 | 727 | { 728 | "137.220.55.93", 729 | 33445, 730 | { 731 | 0xBE, 0x7E, 0xD5, 0x3C, 0xD9, 0x24, 0x81, 0x35, 0x07, 0xBA, 0x71, 0x1F, 0xD4, 0x03, 0x86, 0x06, 732 | 0x2E, 0x6D, 0xC6, 0xF7, 0x90, 0xEF, 0xA1, 0x22, 0xC7, 0x8F, 0x7C, 0xDE, 0xEE, 0x4B, 0x6D, 0x1B 733 | } 734 | }, 735 | 736 | { 737 | "137.220.55.93", 738 | 33445, 739 | { 740 | 0xBE, 0x7E, 0xD5, 0x3C, 0xD9, 0x24, 0x81, 0x35, 0x07, 0xBA, 0x71, 0x1F, 0xD4, 0x03, 0x86, 0x06, 741 | 0x2E, 0x6D, 0xC6, 0xF7, 0x90, 0xEF, 0xA1, 0x22, 0xC7, 0x8F, 0x7C, 0xDE, 0xEE, 0x4B, 0x6D, 0x1B 742 | } 743 | }, 744 | 745 | { 746 | "172.104.215.182", 747 | 3389, 748 | { 749 | 0xDA, 0x2B, 0xD9, 0x27, 0xE0, 0x1C, 0xD0, 0x5E, 0xBC, 0xC2, 0x57, 0x4E, 0xBE, 0x5B, 0xEB, 0xB1, 750 | 0x0F, 0xF5, 0x9A, 0xE0, 0xB2, 0x10, 0x5A, 0x7D, 0x1E, 0x2B, 0x40, 0xE4, 0x9B, 0xB2, 0x02, 0x39 751 | } 752 | }, 753 | 754 | { 755 | "172.104.215.182", 756 | 443, 757 | { 758 | 0xDA, 0x2B, 0xD9, 0x27, 0xE0, 0x1C, 0xD0, 0x5E, 0xBC, 0xC2, 0x57, 0x4E, 0xBE, 0x5B, 0xEB, 0xB1, 759 | 0x0F, 0xF5, 0x9A, 0xE0, 0xB2, 0x10, 0x5A, 0x7D, 0x1E, 0x2B, 0x40, 0xE4, 0x9B, 0xB2, 0x02, 0x39 760 | } 761 | }, 762 | 763 | { 764 | "172.104.215.182", 765 | 33445, 766 | { 767 | 0xDA, 0x2B, 0xD9, 0x27, 0xE0, 0x1C, 0xD0, 0x5E, 0xBC, 0xC2, 0x57, 0x4E, 0xBE, 0x5B, 0xEB, 0xB1, 768 | 0x0F, 0xF5, 0x9A, 0xE0, 0xB2, 0x10, 0x5A, 0x7D, 0x1E, 0x2B, 0x40, 0xE4, 0x9B, 0xB2, 0x02, 0x39 769 | } 770 | }, 771 | 772 | { 773 | "2600:3c03::f03c:93ff:fe7f:6096", 774 | 3389, 775 | { 776 | 0xDA, 0x2B, 0xD9, 0x27, 0xE0, 0x1C, 0xD0, 0x5E, 0xBC, 0xC2, 0x57, 0x4E, 0xBE, 0x5B, 0xEB, 0xB1, 777 | 0x0F, 0xF5, 0x9A, 0xE0, 0xB2, 0x10, 0x5A, 0x7D, 0x1E, 0x2B, 0x40, 0xE4, 0x9B, 0xB2, 0x02, 0x39 778 | } 779 | }, 780 | 781 | { 782 | "2600:3c03::f03c:93ff:fe7f:6096", 783 | 443, 784 | { 785 | 0xDA, 0x2B, 0xD9, 0x27, 0xE0, 0x1C, 0xD0, 0x5E, 0xBC, 0xC2, 0x57, 0x4E, 0xBE, 0x5B, 0xEB, 0xB1, 786 | 0x0F, 0xF5, 0x9A, 0xE0, 0xB2, 0x10, 0x5A, 0x7D, 0x1E, 0x2B, 0x40, 0xE4, 0x9B, 0xB2, 0x02, 0x39 787 | } 788 | }, 789 | 790 | { 791 | "2600:3c03::f03c:93ff:fe7f:6096", 792 | 33445, 793 | { 794 | 0xDA, 0x2B, 0xD9, 0x27, 0xE0, 0x1C, 0xD0, 0x5E, 0xBC, 0xC2, 0x57, 0x4E, 0xBE, 0x5B, 0xEB, 0xB1, 795 | 0x0F, 0xF5, 0x9A, 0xE0, 0xB2, 0x10, 0x5A, 0x7D, 0x1E, 0x2B, 0x40, 0xE4, 0x9B, 0xB2, 0x02, 0x39 796 | } 797 | }, 798 | 799 | { 800 | "114.35.245.150", 801 | 33445, 802 | { 803 | 0x3F, 0x0A, 0x45, 0xA2, 0x68, 0x36, 0x7C, 0x1B, 0xEA, 0x65, 0x2F, 0x25, 0x8C, 0x85, 0xF4, 0xA6, 804 | 0x6D, 0xA7, 0x6B, 0xCA, 0xA6, 0x67, 0xA4, 0x9E, 0x77, 0x0B, 0xCC, 0x49, 0x17, 0xAB, 0x6A, 0x25 805 | } 806 | }, 807 | 808 | { 809 | "114.35.245.150", 810 | 3389, 811 | { 812 | 0x3F, 0x0A, 0x45, 0xA2, 0x68, 0x36, 0x7C, 0x1B, 0xEA, 0x65, 0x2F, 0x25, 0x8C, 0x85, 0xF4, 0xA6, 813 | 0x6D, 0xA7, 0x6B, 0xCA, 0xA6, 0x67, 0xA4, 0x9E, 0x77, 0x0B, 0xCC, 0x49, 0x17, 0xAB, 0x6A, 0x25 814 | } 815 | }, 816 | 817 | { 818 | "114.35.245.150", 819 | 33445, 820 | { 821 | 0x3F, 0x0A, 0x45, 0xA2, 0x68, 0x36, 0x7C, 0x1B, 0xEA, 0x65, 0x2F, 0x25, 0x8C, 0x85, 0xF4, 0xA6, 822 | 0x6D, 0xA7, 0x6B, 0xCA, 0xA6, 0x67, 0xA4, 0x9E, 0x77, 0x0B, 0xCC, 0x49, 0x17, 0xAB, 0x6A, 0x25 823 | } 824 | }, 825 | 826 | { 827 | "114.35.245.150", 828 | 3389, 829 | { 830 | 0x3F, 0x0A, 0x45, 0xA2, 0x68, 0x36, 0x7C, 0x1B, 0xEA, 0x65, 0x2F, 0x25, 0x8C, 0x85, 0xF4, 0xA6, 831 | 0x6D, 0xA7, 0x6B, 0xCA, 0xA6, 0x67, 0xA4, 0x9E, 0x77, 0x0B, 0xCC, 0x49, 0x17, 0xAB, 0x6A, 0x25 832 | } 833 | }, 834 | 835 | { 836 | "104.244.74.69", 837 | 33445, 838 | { 839 | 0x8E, 0x8B, 0x63, 0x29, 0x9B, 0x3D, 0x52, 0x0F, 0xB3, 0x77, 0xFE, 0x51, 0x00, 0xE6, 0x5E, 0x33, 840 | 0x22, 0xF7, 0xAE, 0x5B, 0x20, 0xA0, 0xAC, 0xED, 0x29, 0x81, 0x76, 0x9F, 0xC5, 0xB4, 0x37, 0x25 841 | } 842 | }, 843 | 844 | { 845 | "104.244.74.69", 846 | 443, 847 | { 848 | 0x8E, 0x8B, 0x63, 0x29, 0x9B, 0x3D, 0x52, 0x0F, 0xB3, 0x77, 0xFE, 0x51, 0x00, 0xE6, 0x5E, 0x33, 849 | 0x22, 0xF7, 0xAE, 0x5B, 0x20, 0xA0, 0xAC, 0xED, 0x29, 0x81, 0x76, 0x9F, 0xC5, 0xB4, 0x37, 0x25 850 | } 851 | }, 852 | 853 | { 854 | "104.244.74.69", 855 | 33445, 856 | { 857 | 0x8E, 0x8B, 0x63, 0x29, 0x9B, 0x3D, 0x52, 0x0F, 0xB3, 0x77, 0xFE, 0x51, 0x00, 0xE6, 0x5E, 0x33, 858 | 0x22, 0xF7, 0xAE, 0x5B, 0x20, 0xA0, 0xAC, 0xED, 0x29, 0x81, 0x76, 0x9F, 0xC5, 0xB4, 0x37, 0x25 859 | } 860 | }, 861 | 862 | { 863 | "104.244.74.69", 864 | 443, 865 | { 866 | 0x8E, 0x8B, 0x63, 0x29, 0x9B, 0x3D, 0x52, 0x0F, 0xB3, 0x77, 0xFE, 0x51, 0x00, 0xE6, 0x5E, 0x33, 867 | 0x22, 0xF7, 0xAE, 0x5B, 0x20, 0xA0, 0xAC, 0xED, 0x29, 0x81, 0x76, 0x9F, 0xC5, 0xB4, 0x37, 0x25 868 | } 869 | }, 870 | 871 | { 872 | "188.214.122.30", 873 | 3389, 874 | { 875 | 0x2A, 0x9F, 0x7A, 0x62, 0x05, 0x81, 0xD5, 0xD1, 0xB0, 0x9B, 0x00, 0x46, 0x24, 0x55, 0x92, 0x11, 876 | 0xC5, 0xED, 0x3D, 0x1D, 0x71, 0x2E, 0x80, 0x66, 0xAC, 0xDB, 0x08, 0x96, 0xA7, 0x33, 0x57, 0x05 877 | } 878 | }, 879 | 880 | { 881 | "188.214.122.30", 882 | 33445, 883 | { 884 | 0x2A, 0x9F, 0x7A, 0x62, 0x05, 0x81, 0xD5, 0xD1, 0xB0, 0x9B, 0x00, 0x46, 0x24, 0x55, 0x92, 0x11, 885 | 0xC5, 0xED, 0x3D, 0x1D, 0x71, 0x2E, 0x80, 0x66, 0xAC, 0xDB, 0x08, 0x96, 0xA7, 0x33, 0x57, 0x05 886 | } 887 | }, 888 | 889 | { 890 | "2607:f130:0:f8::4c85:a645", 891 | 33445, 892 | { 893 | 0x8A, 0xFE, 0x1F, 0xC6, 0x42, 0x6E, 0x5B, 0x77, 0xAB, 0x80, 0x31, 0x8E, 0xD6, 0x4F, 0x5F, 0x76, 894 | 0x34, 0x16, 0x95, 0xB9, 0xFB, 0x47, 0xAB, 0x8A, 0xC9, 0x53, 0x7B, 0xF5, 0xEE, 0x9E, 0x9D, 0x29 895 | } 896 | }, 897 | 898 | { 899 | "2607:f130:0:f8::4c85:a645", 900 | 3389, 901 | { 902 | 0x8A, 0xFE, 0x1F, 0xC6, 0x42, 0x6E, 0x5B, 0x77, 0xAB, 0x80, 0x31, 0x8E, 0xD6, 0x4F, 0x5F, 0x76, 903 | 0x34, 0x16, 0x95, 0xB9, 0xFB, 0x47, 0xAB, 0x8A, 0xC9, 0x53, 0x7B, 0xF5, 0xEE, 0x9E, 0x9D, 0x29 904 | } 905 | }, 906 | 907 | }; -------------------------------------------------------------------------------- /tox_bootstrap_json.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "cJSON.h" 8 | #include "log.h" 9 | #include "util.h" 10 | 11 | void do_bootstrap_file(Tox *tox, const char *json_file) 12 | { 13 | char *buffer = NULL; 14 | long length; 15 | 16 | const cJSON *node = NULL; 17 | const cJSON *nodes = NULL; 18 | const cJSON *tcp_ports = NULL; 19 | const cJSON *tcp_port = NULL; 20 | unsigned char key_bin[TOX_PUBLIC_KEY_SIZE]; 21 | 22 | FILE * f = fopen(json_file, "rb"); 23 | 24 | if (f) { 25 | fseek (f, 0, SEEK_END); 26 | length = ftell (f); 27 | fseek (f, 0, SEEK_SET); 28 | buffer = malloc (length); 29 | if (buffer) { 30 | fread (buffer, 1, length, f); 31 | } 32 | fclose (f); 33 | } else { 34 | log_printf(L_INFO, "Could not find Tox bootstrap nodes in file %s. Using hardcoded.\n", json_file); 35 | return; 36 | } 37 | 38 | if (!buffer) { 39 | log_printf(L_WARNING, "Could not read Tox bootstrap nodes from file %s.", json_file); 40 | return; 41 | } 42 | 43 | cJSON *nodes_json = cJSON_Parse(buffer); 44 | if (nodes_json == NULL) { 45 | const char *error_ptr = cJSON_GetErrorPtr(); 46 | if (error_ptr != NULL) { 47 | log_printf(L_WARNING, "Error reading JSON from %s before: %s\n", json_file, error_ptr); 48 | } 49 | goto end; 50 | } 51 | 52 | nodes = cJSON_GetObjectItemCaseSensitive(nodes_json, "nodes"); 53 | cJSON_ArrayForEach(node, nodes) { 54 | cJSON *port = cJSON_GetObjectItemCaseSensitive(node, "port"); 55 | cJSON *ipv4 = cJSON_GetObjectItemCaseSensitive(node, "ipv4"); 56 | cJSON *ipv6 = cJSON_GetObjectItemCaseSensitive(node, "ipv6"); 57 | cJSON *pk = cJSON_GetObjectItemCaseSensitive(node, "public_key"); 58 | 59 | if (!cJSON_IsNumber(port) || !cJSON_IsString(ipv4) || 60 | !cJSON_IsString(ipv6) || !cJSON_IsString(pk) ) { 61 | continue; 62 | } 63 | 64 | if (!is_valid_ipv4(ipv4->valuestring) && !is_valid_ipv6(ipv6->valuestring)) { 65 | log_printf(L_INFO, "Skipping \"%s:%d\" %s\n", ipv4->valuestring, port->valueint, pk->valuestring); 66 | continue; 67 | } 68 | 69 | /* Could have used sodium here, but did not want to change dependencies. Alternative is: 70 | sodium_hex2bin(key_bin, sizeof(key_bin), pk->valuestring, sizeof(pk->valuestring)-1, NULL, NULL, NULL); 71 | */ 72 | hex_string_to_bin(pk->valuestring, sizeof(pk->valuestring)-1, key_bin); 73 | 74 | if(is_valid_ipv4(ipv4->valuestring)) 75 | { 76 | tox_bootstrap(tox, ipv4->valuestring, port->valueint, key_bin, NULL); 77 | log_printf(L_INFO, "Bootstrapping from \"%s:%d\" %s\n", ipv4->valuestring, port->valueint, pk->valuestring); 78 | } 79 | 80 | if(is_valid_ipv6(ipv6->valuestring)) 81 | { 82 | tox_bootstrap(tox, ipv6->valuestring, port->valueint, key_bin, NULL); 83 | log_printf(L_INFO, "Bootstrapping from \"%s:%d\" %s\n", ipv6->valuestring, port->valueint, pk->valuestring); 84 | } 85 | 86 | tcp_ports = cJSON_GetObjectItemCaseSensitive(node, "tcp_ports"); 87 | cJSON_ArrayForEach(tcp_port, tcp_ports) { 88 | if (cJSON_IsNumber(tcp_port)) { 89 | log_printf(L_INFO, " Also adding TCP-realy %d\n", tcp_port->valueint); 90 | tox_add_tcp_relay(tox, ipv4->valuestring, tcp_port->valueint, key_bin, 0); 91 | } 92 | } 93 | } 94 | end: 95 | cJSON_Delete(nodes_json); 96 | free(buffer); 97 | } 98 | -------------------------------------------------------------------------------- /tox_bootstrap_json.h: -------------------------------------------------------------------------------- 1 | #ifndef _TOX_BOOTSTRAP_JSON_H 2 | #define _TOX_BOOTSTRAP_JSON_H 3 | void do_bootstrap_file(Tox *tox, const char * filename); 4 | #endif 5 | -------------------------------------------------------------------------------- /utarray.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | /* a dynamic array implementation using macros 25 | */ 26 | #ifndef UTARRAY_H 27 | #define UTARRAY_H 28 | 29 | #define UTARRAY_VERSION 1.9.9 30 | 31 | #ifdef __GNUC__ 32 | #define _UNUSED_ __attribute__ ((__unused__)) 33 | #else 34 | #define _UNUSED_ 35 | #endif 36 | 37 | #include /* size_t */ 38 | #include /* memset, etc */ 39 | #include /* exit */ 40 | 41 | #define oom() exit(-1) 42 | 43 | typedef void (ctor_f)(void *dst, const void *src); 44 | typedef void (dtor_f)(void *elt); 45 | typedef void (init_f)(void *elt); 46 | typedef struct { 47 | size_t sz; 48 | init_f *init; 49 | ctor_f *copy; 50 | dtor_f *dtor; 51 | } UT_icd; 52 | 53 | typedef struct { 54 | unsigned i,n;/* i: index of next available slot, n: num slots */ 55 | UT_icd icd; /* initializer, copy and destructor functions */ 56 | char *d; /* n slots of size icd->sz*/ 57 | } UT_array; 58 | 59 | #define utarray_init(a,_icd) do { \ 60 | memset(a,0,sizeof(UT_array)); \ 61 | (a)->icd=*_icd; \ 62 | } while(0) 63 | 64 | #define utarray_done(a) do { \ 65 | if ((a)->n) { \ 66 | if ((a)->icd.dtor) { \ 67 | size_t _ut_i; \ 68 | for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ 69 | (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ 70 | } \ 71 | } \ 72 | free((a)->d); \ 73 | } \ 74 | (a)->n=0; \ 75 | } while(0) 76 | 77 | #define utarray_new(a,_icd) do { \ 78 | a=(UT_array*)malloc(sizeof(UT_array)); \ 79 | utarray_init(a,_icd); \ 80 | } while(0) 81 | 82 | #define utarray_free(a) do { \ 83 | utarray_done(a); \ 84 | free(a); \ 85 | } while(0) 86 | 87 | #define utarray_reserve(a,by) do { \ 88 | if (((a)->i+by) > ((a)->n)) { \ 89 | while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ 90 | if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd.sz)) == NULL) oom(); \ 91 | } \ 92 | } while(0) 93 | 94 | #define utarray_push_back(a,p) do { \ 95 | utarray_reserve(a,1); \ 96 | if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \ 97 | else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \ 98 | } while(0) 99 | 100 | #define utarray_pop_back(a) do { \ 101 | if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \ 102 | else { (a)->i--; } \ 103 | } while(0) 104 | 105 | #define utarray_extend_back(a) do { \ 106 | utarray_reserve(a,1); \ 107 | if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \ 108 | else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \ 109 | (a)->i++; \ 110 | } while(0) 111 | 112 | #define utarray_len(a) ((a)->i) 113 | 114 | #define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) 115 | #define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd.sz*(j) ))) 116 | 117 | #define utarray_insert(a,p,j) do { \ 118 | if (j > (a)->i) utarray_resize(a,j); \ 119 | utarray_reserve(a,1); \ 120 | if ((j) < (a)->i) { \ 121 | memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ 122 | ((a)->i - (j))*((a)->icd.sz)); \ 123 | } \ 124 | if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \ 125 | else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \ 126 | (a)->i++; \ 127 | } while(0) 128 | 129 | #define utarray_inserta(a,w,j) do { \ 130 | if (utarray_len(w) == 0) break; \ 131 | if (j > (a)->i) utarray_resize(a,j); \ 132 | utarray_reserve(a,utarray_len(w)); \ 133 | if ((j) < (a)->i) { \ 134 | memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ 135 | _utarray_eltptr(a,j), \ 136 | ((a)->i - (j))*((a)->icd.sz)); \ 137 | } \ 138 | if ((a)->icd.copy) { \ 139 | size_t _ut_i; \ 140 | for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ 141 | (a)->icd.copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \ 142 | } \ 143 | } else { \ 144 | memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ 145 | utarray_len(w)*((a)->icd.sz)); \ 146 | } \ 147 | (a)->i += utarray_len(w); \ 148 | } while(0) 149 | 150 | #define utarray_resize(dst,num) do { \ 151 | size_t _ut_i; \ 152 | if (dst->i > (size_t)(num)) { \ 153 | if ((dst)->icd.dtor) { \ 154 | for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \ 155 | (dst)->icd.dtor(utarray_eltptr(dst,_ut_i)); \ 156 | } \ 157 | } \ 158 | } else if (dst->i < (size_t)(num)) { \ 159 | utarray_reserve(dst,num-dst->i); \ 160 | if ((dst)->icd.init) { \ 161 | for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \ 162 | (dst)->icd.init(utarray_eltptr(dst,_ut_i)); \ 163 | } \ 164 | } else { \ 165 | memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd.sz*(num-dst->i)); \ 166 | } \ 167 | } \ 168 | dst->i = num; \ 169 | } while(0) 170 | 171 | #define utarray_concat(dst,src) do { \ 172 | utarray_inserta((dst),(src),utarray_len(dst)); \ 173 | } while(0) 174 | 175 | #define utarray_erase(a,pos,len) do { \ 176 | if ((a)->icd.dtor) { \ 177 | size_t _ut_i; \ 178 | for(_ut_i=0; _ut_i < len; _ut_i++) { \ 179 | (a)->icd.dtor(utarray_eltptr((a),pos+_ut_i)); \ 180 | } \ 181 | } \ 182 | if ((a)->i > (pos+len)) { \ 183 | memmove( _utarray_eltptr((a),pos), _utarray_eltptr((a),pos+len), \ 184 | (((a)->i)-(pos+len))*((a)->icd.sz)); \ 185 | } \ 186 | (a)->i -= (len); \ 187 | } while(0) 188 | 189 | #define utarray_renew(a,u) do { \ 190 | if (a) utarray_clear(a); \ 191 | else utarray_new((a),(u)); \ 192 | } while(0) 193 | 194 | #define utarray_clear(a) do { \ 195 | if ((a)->i > 0) { \ 196 | if ((a)->icd.dtor) { \ 197 | size_t _ut_i; \ 198 | for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ 199 | (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ 200 | } \ 201 | } \ 202 | (a)->i = 0; \ 203 | } \ 204 | } while(0) 205 | 206 | #define utarray_sort(a,cmp) do { \ 207 | qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \ 208 | } while(0) 209 | 210 | #define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp) 211 | 212 | #define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) 213 | #define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) 214 | #define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL)) 215 | #define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) 216 | #define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(size_t)(a)->icd.sz) : -1) 217 | 218 | /* last we pre-define a few icd for common utarrays of ints and strings */ 219 | static void utarray_str_cpy(void *dst, const void *src) { 220 | char **_src = (char**)src, **_dst = (char**)dst; 221 | *_dst = (*_src == NULL) ? NULL : strdup(*_src); 222 | } 223 | static void utarray_str_dtor(void *elt) { 224 | char **eltc = (char**)elt; 225 | if (*eltc) free(*eltc); 226 | } 227 | static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; 228 | static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL}; 229 | static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL}; 230 | 231 | 232 | #endif /* UTARRAY_H */ 233 | -------------------------------------------------------------------------------- /util.c: -------------------------------------------------------------------------------- 1 | #include "log.h" 2 | #include "util.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void writechecksum(uint8_t *address) 13 | { 14 | uint8_t *checksum = address + 36; 15 | uint32_t i; 16 | 17 | for (i = 0; i < 36; ++i) 18 | checksum[i % 2] ^= address[i]; 19 | } 20 | 21 | /* From utox/util.c */ 22 | void to_hex(char_t *a, const char_t *p, int size) 23 | { 24 | char_t b, c; 25 | const char_t *end = p + size; 26 | 27 | while(p != end) { 28 | b = *p++; 29 | 30 | c = (b & 0xF); 31 | b = (b >> 4); 32 | 33 | if(b < 10) { 34 | *a++ = b + '0'; 35 | } else { 36 | *a++ = b - 10 + 'A'; 37 | } 38 | 39 | if(c < 10) { 40 | *a++ = c + '0'; 41 | } else { 42 | *a++ = c - 10 + 'A'; 43 | } 44 | } 45 | *a = '\0'; 46 | } 47 | 48 | /* From utox/util.c */ 49 | void id_to_string(char_t *dest, const char_t *src) 50 | { 51 | to_hex(dest, src, TOX_ADDRESS_SIZE); 52 | } 53 | 54 | /* From utox/util.c */ 55 | int string_to_id(char_t *w, char_t *a) 56 | { 57 | char_t *end = w + TOX_ADDRESS_SIZE; 58 | while(w != end) { 59 | char_t c, v; 60 | 61 | c = *a++; 62 | if(c >= '0' && c <= '9') { 63 | v = (c - '0') << 4; 64 | } else if(c >= 'A' && c <= 'F') { 65 | v = (c - 'A' + 10) << 4; 66 | } else if(c >= 'a' && c <= 'f') { 67 | v = (c - 'a' + 10) << 4; 68 | } else { 69 | return 0; 70 | } 71 | 72 | c = *a++; 73 | if(c >= '0' && c <= '9') { 74 | v |= (c - '0'); 75 | } else if(c >= 'A' && c <= 'F') { 76 | v |= (c - 'A' + 10); 77 | } else if(c >= 'a' && c <= 'f') { 78 | v |= (c - 'a' + 10); 79 | } else { 80 | return 0; 81 | } 82 | 83 | *w++ = v; 84 | } 85 | 86 | return 1; 87 | } 88 | 89 | /* Parse the -L parameter */ 90 | /* 0 = success */ 91 | int parse_local_port_forward(char *string, int *local_port, char **hostname, int *remote_port) 92 | { 93 | char *lport; 94 | char *host; 95 | char *rport; 96 | 97 | /* First replace all @ with :, ':' is forbidden in some environments */ 98 | char *p = string; 99 | while(*p) 100 | { 101 | if(*p == '@') *p = ':'; 102 | p++; 103 | } 104 | 105 | lport = strtok(string, ":"); 106 | host = strtok(NULL, ":"); 107 | rport = strtok(NULL, ":"); 108 | 109 | if(!lport || !host || !rport) 110 | { 111 | return -1; 112 | } 113 | 114 | *local_port = atoi(lport); 115 | *hostname = host; 116 | *remote_port = atoi(rport); 117 | 118 | return 0; 119 | } 120 | 121 | /* Parse the -W parameter */ 122 | /* 0 = success */ 123 | int parse_pipe_port_forward(char *string, char **hostname, int *remote_port) 124 | { 125 | char *host; 126 | char *rport; 127 | 128 | /* First replace all @ with :, ':' is forbidden in some environments */ 129 | char *p = string; 130 | while(*p) 131 | { 132 | if(*p == '@') *p = ':'; 133 | p++; 134 | } 135 | 136 | host = strtok(string, ":"); 137 | rport = strtok(NULL, ":"); 138 | 139 | if(!host || !rport) 140 | { 141 | return -1; 142 | } 143 | 144 | *hostname = host; 145 | *remote_port = atoi(rport); 146 | 147 | return 0; 148 | } 149 | 150 | void* file_raw(char *path, uint32_t *size) 151 | { 152 | FILE *file; 153 | char *data; 154 | int len; 155 | 156 | file = fopen(path, "rb"); 157 | if(!file) { 158 | log_printf(L_WARNING, "File not found (%s)\n", path); 159 | return NULL; 160 | } 161 | 162 | fseek(file, 0, SEEK_END); 163 | len = ftell(file); 164 | if(len <= 0) 165 | { 166 | fclose(file); 167 | return NULL; 168 | } 169 | data = malloc(len); 170 | if(!data) { 171 | fclose(file); 172 | return NULL; 173 | } 174 | 175 | fseek(file, 0, SEEK_SET); 176 | 177 | if(fread(data, len, 1, file) != 1) { 178 | log_printf(L_WARNING, "Read error (%s)\n", path); 179 | fclose(file); 180 | free(data); 181 | return NULL; 182 | } 183 | 184 | fclose(file); 185 | 186 | log_printf(L_DEBUG, "Read %u bytes (%s)\n", len, path); 187 | 188 | if(size) { 189 | *size = len; 190 | } 191 | return data; 192 | } 193 | 194 | const char *readable_connection_status(TOX_CONNECTION status) 195 | { 196 | switch(status) 197 | { 198 | case TOX_CONNECTION_NONE: 199 | return "There is no connection"; 200 | case TOX_CONNECTION_TCP: 201 | return "A TCP connection has been established (via TCP relay)"; 202 | case TOX_CONNECTION_UDP: 203 | return "An UDP connection has been established"; 204 | default: 205 | log_printf(L_WARNING, "Received unknown connection status %d\n", (int)status); 206 | return "Unknown connection status"; 207 | } 208 | } 209 | 210 | /* From https://github.com/TokTok/c-toxcore/blob/master/other/fun/cracker.c */ 211 | size_t hex_string_to_bin(const char *hex_string, size_t hex_len, uint8_t *bytes) 212 | { 213 | size_t i; 214 | const char *pos = hex_string; 215 | // make even 216 | for (i = 0; i < hex_len / 2; ++i, pos += 2) { 217 | uint8_t val; 218 | if (sscanf(pos, "%02hhx", &val) != 1) { 219 | return 0; 220 | } 221 | bytes[i] = val; 222 | } 223 | if (i * 2 < hex_len) { 224 | uint8_t val; 225 | if (sscanf(pos, "%hhx", &val) != 1) { 226 | return 0; 227 | } 228 | bytes[i] = (uint8_t)(val << 4); 229 | ++i; 230 | } 231 | return i; 232 | } 233 | 234 | /* Very stupid test to filter out hostnames */ 235 | bool is_valid_ipv4(const char *ip_address) 236 | { 237 | unsigned int a,b,c,d; 238 | return sscanf(ip_address,"%u.%u.%u.%u", &a, &b, &c, &d) == 4; 239 | } 240 | 241 | bool is_valid_ipv6(const char *ip_address) 242 | { 243 | struct in6_addr result; 244 | return (inet_pton(AF_INET6, ip_address, &result) == 1); 245 | } 246 | 247 | void save_printable_tox_id(const unsigned char *tox_printable_id, const char *path) 248 | { 249 | FILE *f = fopen(path, "w"); 250 | if(!f) 251 | { 252 | log_printf(L_ERROR, "Could not write to %s: %d %s", path, errno, strerror(errno)); 253 | } 254 | log_printf(L_DEBUG, "Writing Tox ID to %s", path); 255 | fputs((char*)tox_printable_id, f); 256 | fclose(f); 257 | } 258 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_H 2 | #define _UTIL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #define countof(x) (sizeof(x)/sizeof(*(x))) 8 | #define char_t unsigned char 9 | 10 | void writechecksum(uint8_t *address); 11 | void to_hex(char_t *a, const char_t *p, int size); 12 | void id_to_string(char_t *dest, const char_t *src); 13 | int string_to_id(char_t *w, char_t *a); 14 | void* file_raw(char *path, uint32_t *size); 15 | const char *readable_connection_status(TOX_CONNECTION status); 16 | int parse_local_port_forward(char *string, int *local_port, char **hostname, int *remote_port); 17 | int parse_pipe_port_forward(char *string, char **hostname, int *remote_port); 18 | size_t hex_string_to_bin(const char *hex_string, size_t hex_len, uint8_t *bytes); 19 | bool is_valid_ipv4(const char *ip_address); 20 | bool is_valid_ipv6(const char *ip_address); 21 | void save_printable_tox_id(const unsigned char *tox_printable_id, const char *path); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /utstring.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2014, Troy D. Hanson http://troydhanson.github.com/uthash/ 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 12 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 13 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 14 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 15 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 16 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 18 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 19 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | */ 23 | 24 | /* a dynamic string implementation using macros 25 | */ 26 | #ifndef UTSTRING_H 27 | #define UTSTRING_H 28 | 29 | #define UTSTRING_VERSION 1.9.9 30 | 31 | #ifdef __GNUC__ 32 | #define _UNUSED_ __attribute__ ((__unused__)) 33 | #else 34 | #define _UNUSED_ 35 | #endif 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #define oom() exit(-1) 42 | 43 | typedef struct { 44 | char *d; 45 | size_t n; /* allocd size */ 46 | size_t i; /* index of first unused byte */ 47 | } UT_string; 48 | 49 | #define utstring_reserve(s,amt) \ 50 | do { \ 51 | if (((s)->n - (s)->i) < (size_t)(amt)) { \ 52 | (s)->d = (char*)realloc((s)->d, (s)->n + amt); \ 53 | if ((s)->d == NULL) oom(); \ 54 | (s)->n += amt; \ 55 | } \ 56 | } while(0) 57 | 58 | #define utstring_init(s) \ 59 | do { \ 60 | (s)->n = 0; (s)->i = 0; (s)->d = NULL; \ 61 | utstring_reserve(s,100); \ 62 | (s)->d[0] = '\0'; \ 63 | } while(0) 64 | 65 | #define utstring_done(s) \ 66 | do { \ 67 | if ((s)->d != NULL) free((s)->d); \ 68 | (s)->n = 0; \ 69 | } while(0) 70 | 71 | #define utstring_free(s) \ 72 | do { \ 73 | utstring_done(s); \ 74 | free(s); \ 75 | } while(0) 76 | 77 | #define utstring_new(s) \ 78 | do { \ 79 | s = (UT_string*)calloc(sizeof(UT_string),1); \ 80 | if (!s) oom(); \ 81 | utstring_init(s); \ 82 | } while(0) 83 | 84 | #define utstring_renew(s) \ 85 | do { \ 86 | if (s) { \ 87 | utstring_clear(s); \ 88 | } else { \ 89 | utstring_new(s); \ 90 | } \ 91 | } while(0) 92 | 93 | #define utstring_clear(s) \ 94 | do { \ 95 | (s)->i = 0; \ 96 | (s)->d[0] = '\0'; \ 97 | } while(0) 98 | 99 | #define utstring_bincpy(s,b,l) \ 100 | do { \ 101 | utstring_reserve((s),(l)+1); \ 102 | if (l) memcpy(&(s)->d[(s)->i], b, l); \ 103 | (s)->i += l; \ 104 | (s)->d[(s)->i]='\0'; \ 105 | } while(0) 106 | 107 | #define utstring_concat(dst,src) \ 108 | do { \ 109 | utstring_reserve((dst),((src)->i)+1); \ 110 | if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \ 111 | (dst)->i += (src)->i; \ 112 | (dst)->d[(dst)->i]='\0'; \ 113 | } while(0) 114 | 115 | #define utstring_len(s) ((unsigned)((s)->i)) 116 | 117 | #define utstring_body(s) ((s)->d) 118 | 119 | _UNUSED_ static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) { 120 | int n; 121 | va_list cp; 122 | while (1) { 123 | #ifdef _WIN32 124 | cp = ap; 125 | #else 126 | va_copy(cp, ap); 127 | #endif 128 | n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp); 129 | va_end(cp); 130 | 131 | if ((n > -1) && ((size_t) n < (s->n-s->i))) { 132 | s->i += n; 133 | return; 134 | } 135 | 136 | /* Else try again with more space. */ 137 | if (n > -1) utstring_reserve(s,n+1); /* exact */ 138 | else utstring_reserve(s,(s->n)*2); /* 2x */ 139 | } 140 | } 141 | #ifdef __GNUC__ 142 | /* support printf format checking (2=the format string, 3=start of varargs) */ 143 | static void utstring_printf(UT_string *s, const char *fmt, ...) 144 | __attribute__ (( format( printf, 2, 3) )); 145 | #endif 146 | _UNUSED_ static void utstring_printf(UT_string *s, const char *fmt, ...) { 147 | va_list ap; 148 | va_start(ap,fmt); 149 | utstring_printf_va(s,fmt,ap); 150 | va_end(ap); 151 | } 152 | 153 | /******************************************************************************* 154 | * begin substring search functions * 155 | ******************************************************************************/ 156 | /* Build KMP table from left to right. */ 157 | _UNUSED_ static void _utstring_BuildTable( 158 | const char *P_Needle, 159 | size_t P_NeedleLen, 160 | long *P_KMP_Table) 161 | { 162 | long i, j; 163 | 164 | i = 0; 165 | j = i - 1; 166 | P_KMP_Table[i] = j; 167 | while (i < (long) P_NeedleLen) 168 | { 169 | while ( (j > -1) && (P_Needle[i] != P_Needle[j]) ) 170 | { 171 | j = P_KMP_Table[j]; 172 | } 173 | i++; 174 | j++; 175 | if (i < (long) P_NeedleLen) 176 | { 177 | if (P_Needle[i] == P_Needle[j]) 178 | { 179 | P_KMP_Table[i] = P_KMP_Table[j]; 180 | } 181 | else 182 | { 183 | P_KMP_Table[i] = j; 184 | } 185 | } 186 | else 187 | { 188 | P_KMP_Table[i] = j; 189 | } 190 | } 191 | 192 | return; 193 | } 194 | 195 | 196 | /* Build KMP table from right to left. */ 197 | _UNUSED_ static void _utstring_BuildTableR( 198 | const char *P_Needle, 199 | size_t P_NeedleLen, 200 | long *P_KMP_Table) 201 | { 202 | long i, j; 203 | 204 | i = P_NeedleLen - 1; 205 | j = i + 1; 206 | P_KMP_Table[i + 1] = j; 207 | while (i >= 0) 208 | { 209 | while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) ) 210 | { 211 | j = P_KMP_Table[j + 1]; 212 | } 213 | i--; 214 | j--; 215 | if (i >= 0) 216 | { 217 | if (P_Needle[i] == P_Needle[j]) 218 | { 219 | P_KMP_Table[i + 1] = P_KMP_Table[j + 1]; 220 | } 221 | else 222 | { 223 | P_KMP_Table[i + 1] = j; 224 | } 225 | } 226 | else 227 | { 228 | P_KMP_Table[i + 1] = j; 229 | } 230 | } 231 | 232 | return; 233 | } 234 | 235 | 236 | /* Search data from left to right. ( Multiple search mode. ) */ 237 | _UNUSED_ static long _utstring_find( 238 | const char *P_Haystack, 239 | size_t P_HaystackLen, 240 | const char *P_Needle, 241 | size_t P_NeedleLen, 242 | long *P_KMP_Table) 243 | { 244 | long i, j; 245 | long V_FindPosition = -1; 246 | 247 | /* Search from left to right. */ 248 | i = j = 0; 249 | while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) ) 250 | { 251 | while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) ) 252 | { 253 | i = P_KMP_Table[i]; 254 | } 255 | i++; 256 | j++; 257 | if (i >= (int)P_NeedleLen) 258 | { 259 | /* Found. */ 260 | V_FindPosition = j - i; 261 | break; 262 | } 263 | } 264 | 265 | return V_FindPosition; 266 | } 267 | 268 | 269 | /* Search data from right to left. ( Multiple search mode. ) */ 270 | _UNUSED_ static long _utstring_findR( 271 | const char *P_Haystack, 272 | size_t P_HaystackLen, 273 | const char *P_Needle, 274 | size_t P_NeedleLen, 275 | long *P_KMP_Table) 276 | { 277 | long i, j; 278 | long V_FindPosition = -1; 279 | 280 | /* Search from right to left. */ 281 | j = (P_HaystackLen - 1); 282 | i = (P_NeedleLen - 1); 283 | while ( (j >= 0) && (j >= i) ) 284 | { 285 | while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) ) 286 | { 287 | i = P_KMP_Table[i + 1]; 288 | } 289 | i--; 290 | j--; 291 | if (i < 0) 292 | { 293 | /* Found. */ 294 | V_FindPosition = j + 1; 295 | break; 296 | } 297 | } 298 | 299 | return V_FindPosition; 300 | } 301 | 302 | 303 | /* Search data from left to right. ( One time search mode. ) */ 304 | _UNUSED_ static long utstring_find( 305 | UT_string *s, 306 | long P_StartPosition, /* Start from 0. -1 means last position. */ 307 | const char *P_Needle, 308 | size_t P_NeedleLen) 309 | { 310 | long V_StartPosition; 311 | long V_HaystackLen; 312 | long *V_KMP_Table; 313 | long V_FindPosition = -1; 314 | 315 | if (P_StartPosition < 0) 316 | { 317 | V_StartPosition = s->i + P_StartPosition; 318 | } 319 | else 320 | { 321 | V_StartPosition = P_StartPosition; 322 | } 323 | V_HaystackLen = s->i - V_StartPosition; 324 | if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) 325 | { 326 | V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); 327 | if (V_KMP_Table != NULL) 328 | { 329 | _utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table); 330 | 331 | V_FindPosition = _utstring_find(s->d + V_StartPosition, 332 | V_HaystackLen, 333 | P_Needle, 334 | P_NeedleLen, 335 | V_KMP_Table); 336 | if (V_FindPosition >= 0) 337 | { 338 | V_FindPosition += V_StartPosition; 339 | } 340 | 341 | free(V_KMP_Table); 342 | } 343 | } 344 | 345 | return V_FindPosition; 346 | } 347 | 348 | 349 | /* Search data from right to left. ( One time search mode. ) */ 350 | _UNUSED_ static long utstring_findR( 351 | UT_string *s, 352 | long P_StartPosition, /* Start from 0. -1 means last position. */ 353 | const char *P_Needle, 354 | size_t P_NeedleLen) 355 | { 356 | long V_StartPosition; 357 | long V_HaystackLen; 358 | long *V_KMP_Table; 359 | long V_FindPosition = -1; 360 | 361 | if (P_StartPosition < 0) 362 | { 363 | V_StartPosition = s->i + P_StartPosition; 364 | } 365 | else 366 | { 367 | V_StartPosition = P_StartPosition; 368 | } 369 | V_HaystackLen = V_StartPosition + 1; 370 | if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) ) 371 | { 372 | V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1)); 373 | if (V_KMP_Table != NULL) 374 | { 375 | _utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table); 376 | 377 | V_FindPosition = _utstring_findR(s->d, 378 | V_HaystackLen, 379 | P_Needle, 380 | P_NeedleLen, 381 | V_KMP_Table); 382 | 383 | free(V_KMP_Table); 384 | } 385 | } 386 | 387 | return V_FindPosition; 388 | } 389 | /******************************************************************************* 390 | * end substring search functions * 391 | ******************************************************************************/ 392 | 393 | #endif /* UTSTRING_H */ 394 | --------------------------------------------------------------------------------