[tor-commits] [orbot/master] remove old embedded badvpn_dns

n8fr8 at torproject.org n8fr8 at torproject.org
Fri Apr 3 17:04:08 UTC 2015


commit 7774ca3b245957b6cef7b774ce117b29a98dab6e
Author: Nathan Freitas <nathan at freitas.net>
Date:   Fri Apr 3 12:22:54 2015 -0400

    remove old embedded badvpn_dns
---
 external/badvpn_dns/Android.mk                     |   75 -
 external/badvpn_dns/CMakeLists.txt                 |  408 --
 external/badvpn_dns/COPYING                        |   24 -
 external/badvpn_dns/ChangeLog                      |  216 -
 external/badvpn_dns/INSTALL                        |   76 -
 external/badvpn_dns/INSTALL-WINDOWS                |   72 -
 external/badvpn_dns/arpprobe/BArpProbe.c           |  359 --
 external/badvpn_dns/arpprobe/BArpProbe.h           |   80 -
 external/badvpn_dns/arpprobe/CMakeLists.txt        |    1 -
 external/badvpn_dns/badvpn.7                       |  324 --
 external/badvpn_dns/base/BLog.c                    |   96 -
 external/badvpn_dns/base/BLog.h                    |  402 --
 external/badvpn_dns/base/BLog_syslog.c             |  150 -
 external/badvpn_dns/base/BLog_syslog.h             |   42 -
 external/badvpn_dns/base/BMutex.h                  |  101 -
 external/badvpn_dns/base/BPending.c                |  205 -
 external/badvpn_dns/base/BPending.h                |  250 -
 external/badvpn_dns/base/BPending_list.h           |    4 -
 external/badvpn_dns/base/CMakeLists.txt            |   13 -
 external/badvpn_dns/base/DebugObject.c             |   39 -
 external/badvpn_dns/base/DebugObject.h             |  147 -
 external/badvpn_dns/blog_channels.txt              |  145 -
 external/badvpn_dns/blog_generator/blog.php        |  121 -
 .../badvpn_dns/blog_generator/blog_functions.php   |   35 -
 external/badvpn_dns/bproto/BProto.h                |   85 -
 .../badvpn_dns/bproto_generator/ProtoParser.lime   |   99 -
 .../badvpn_dns/bproto_generator/ProtoParser.php    |  560 ---
 external/badvpn_dns/bproto_generator/bproto.php    |  115 -
 .../bproto_generator/bproto_functions.php          |  777 ----
 external/badvpn_dns/client/CMakeLists.txt          |   30 -
 external/badvpn_dns/client/DPReceive.c             |  324 --
 external/badvpn_dns/client/DPReceive.h             |   98 -
 external/badvpn_dns/client/DPRelay.c               |  307 --
 external/badvpn_dns/client/DPRelay.h               |   89 -
 external/badvpn_dns/client/DataProto.c             |  566 ---
 external/badvpn_dns/client/DataProto.h             |  237 -
 .../badvpn_dns/client/DataProtoKeepaliveSource.c   |   72 -
 .../badvpn_dns/client/DataProtoKeepaliveSource.h   |   73 -
 external/badvpn_dns/client/DatagramPeerIO.c        |  425 --
 external/badvpn_dns/client/DatagramPeerIO.h        |  271 --
 .../badvpn_dns/client/FragmentProtoAssembler.c     |  469 --
 .../badvpn_dns/client/FragmentProtoAssembler.h     |  134 -
 .../client/FragmentProtoAssembler_tree.h           |    9 -
 .../badvpn_dns/client/FragmentProtoDisassembler.c  |  229 -
 .../badvpn_dns/client/FragmentProtoDisassembler.h  |  109 -
 external/badvpn_dns/client/FrameDecider.c          |  795 ----
 external/badvpn_dns/client/FrameDecider.h          |  196 -
 .../badvpn_dns/client/FrameDecider_groups_tree.h   |    9 -
 .../badvpn_dns/client/FrameDecider_macs_tree.h     |    9 -
 .../client/FrameDecider_multicast_tree.h           |    9 -
 external/badvpn_dns/client/PasswordListener.c      |  374 --
 external/badvpn_dns/client/PasswordListener.h      |  156 -
 external/badvpn_dns/client/PeerChat.c              |  433 --
 external/badvpn_dns/client/PeerChat.h              |  123 -
 external/badvpn_dns/client/SCOutmsgEncoder.c       |  104 -
 external/badvpn_dns/client/SCOutmsgEncoder.h       |   76 -
 external/badvpn_dns/client/SPProtoDecoder.c        |  398 --
 external/badvpn_dns/client/SPProtoDecoder.h        |  171 -
 external/badvpn_dns/client/SPProtoEncoder.c        |  436 --
 external/badvpn_dns/client/SPProtoEncoder.h        |  172 -
 external/badvpn_dns/client/SimpleStreamBuffer.c    |  144 -
 external/badvpn_dns/client/SimpleStreamBuffer.h    |   52 -
 external/badvpn_dns/client/SinglePacketSource.c    |   85 -
 external/badvpn_dns/client/SinglePacketSource.h    |   73 -
 external/badvpn_dns/client/StreamPeerIO.c          |  712 ---
 external/badvpn_dns/client/StreamPeerIO.h          |  222 -
 external/badvpn_dns/client/badvpn-client.8         |  316 --
 external/badvpn_dns/client/client.c                | 2997 ------------
 external/badvpn_dns/client/client.h                |  193 -
 .../badvpn_dns/cmake/modules/COPYING-CMAKE-SCRIPTS |   22 -
 external/badvpn_dns/cmake/modules/FindGLIB2.cmake  |   52 -
 .../cmake/modules/FindLibraryWithDebug.cmake       |  113 -
 external/badvpn_dns/cmake/modules/FindNSPR.cmake   |   57 -
 external/badvpn_dns/cmake/modules/FindNSS.cmake    |   57 -
 .../badvpn_dns/cmake/modules/FindOpenSSL.cmake     |   72 -
 external/badvpn_dns/compile-tun2sock.sh            |  112 -
 external/badvpn_dns/compile-udpgw.sh               |   84 -
 external/badvpn_dns/dhcpclient/BDHCPClient.c       |  340 --
 external/badvpn_dns/dhcpclient/BDHCPClient.h       |   87 -
 external/badvpn_dns/dhcpclient/BDHCPClientCore.c   |  860 ----
 external/badvpn_dns/dhcpclient/BDHCPClientCore.h   |  114 -
 external/badvpn_dns/dhcpclient/CMakeLists.txt      |   10 -
 external/badvpn_dns/dhcpclient/DHCPIpUdpDecoder.c  |  137 -
 external/badvpn_dns/dhcpclient/DHCPIpUdpDecoder.h  |   49 -
 external/badvpn_dns/dhcpclient/DHCPIpUdpEncoder.c  |  119 -
 external/badvpn_dns/dhcpclient/DHCPIpUdpEncoder.h  |   49 -
 external/badvpn_dns/dostest/CMakeLists.txt         |   10 -
 external/badvpn_dns/dostest/StreamBuffer.c         |  147 -
 external/badvpn_dns/dostest/StreamBuffer.h         |   70 -
 external/badvpn_dns/dostest/dostest-attacker.c     |  512 --
 external/badvpn_dns/dostest/dostest-server.c       |  567 ---
 external/badvpn_dns/examples/CMakeLists.txt        |   97 -
 external/badvpn_dns/examples/FastPacketSource.h    |   79 -
 external/badvpn_dns/examples/RandomPacketSink.h    |  116 -
 external/badvpn_dns/examples/TimerPacketSink.h     |   97 -
 external/badvpn_dns/examples/arpprobe_test.c       |  131 -
 external/badvpn_dns/examples/bavl_test.c           |  129 -
 external/badvpn_dns/examples/bencryption_bench.c   |  146 -
 external/badvpn_dns/examples/bprocess_example.c    |  140 -
 external/badvpn_dns/examples/brandom2_test.c       |   65 -
 external/badvpn_dns/examples/btimer_example.c      |   84 -
 external/badvpn_dns/examples/cavl_test.c           |  285 --
 external/badvpn_dns/examples/cavl_test_tree.h      |   23 -
 external/badvpn_dns/examples/dhcpclient_test.c     |  159 -
 external/badvpn_dns/examples/emscripten_test.c     |   71 -
 external/badvpn_dns/examples/fairqueue_test.c      |  145 -
 external/badvpn_dns/examples/fairqueue_test2.c     |   93 -
 external/badvpn_dns/examples/indexedlist_test.c    |   95 -
 external/badvpn_dns/examples/ipaddr6_test.c        |  169 -
 external/badvpn_dns/examples/ncd_parser_test.c     |  294 --
 external/badvpn_dns/examples/ncd_tokenizer_test.c  |  149 -
 .../badvpn_dns/examples/ncd_value_parser_test.c    |   78 -
 .../badvpn_dns/examples/ncdinterfacemonitor_test.c |  150 -
 external/badvpn_dns/examples/ncdudevmanager_test.c |  161 -
 external/badvpn_dns/examples/ncdudevmonitor_test.c |  152 -
 external/badvpn_dns/examples/ncdval_test.c         |  380 --
 external/badvpn_dns/examples/ncdvalcons_test.c     |  111 -
 external/badvpn_dns/examples/parse_number_test.c   |  130 -
 external/badvpn_dns/examples/predicate_test.c      |  116 -
 external/badvpn_dns/examples/savl_test.c           |  135 -
 external/badvpn_dns/examples/savl_test_tree.h      |    9 -
 external/badvpn_dns/examples/stdin_input.c         |  138 -
 external/badvpn_dns/examples/substring_test.c      |  204 -
 external/badvpn_dns/fix_flex.php                   |   10 -
 external/badvpn_dns/flooder/CMakeLists.txt         |    7 -
 external/badvpn_dns/flooder/flooder.c              |  671 ---
 external/badvpn_dns/flooder/flooder.h              |   37 -
 external/badvpn_dns/flow/BufferWriter.c            |  112 -
 external/badvpn_dns/flow/BufferWriter.h            |  107 -
 external/badvpn_dns/flow/CMakeLists.txt            |   31 -
 external/badvpn_dns/flow/LineBuffer.c              |  140 -
 external/badvpn_dns/flow/LineBuffer.h              |   54 -
 external/badvpn_dns/flow/PacketBuffer.c            |  131 -
 external/badvpn_dns/flow/PacketBuffer.h            |   77 -
 external/badvpn_dns/flow/PacketCopier.c            |  136 -
 external/badvpn_dns/flow/PacketCopier.h            |   90 -
 external/badvpn_dns/flow/PacketPassConnector.c     |  125 -
 external/badvpn_dns/flow/PacketPassConnector.h     |  102 -
 external/badvpn_dns/flow/PacketPassFairQueue.c     |  405 --
 external/badvpn_dns/flow/PacketPassFairQueue.h     |  204 -
 .../badvpn_dns/flow/PacketPassFairQueue_tree.h     |    7 -
 external/badvpn_dns/flow/PacketPassFifoQueue.c     |  241 -
 external/badvpn_dns/flow/PacketPassFifoQueue.h     |   76 -
 external/badvpn_dns/flow/PacketPassInterface.c     |   68 -
 external/badvpn_dns/flow/PacketPassInterface.h     |  236 -
 external/badvpn_dns/flow/PacketPassNotifier.c      |  103 -
 external/badvpn_dns/flow/PacketPassNotifier.h      |   99 -
 external/badvpn_dns/flow/PacketPassPriorityQueue.c |  283 --
 external/badvpn_dns/flow/PacketPassPriorityQueue.h |  192 -
 .../badvpn_dns/flow/PacketPassPriorityQueue_tree.h |    7 -
 external/badvpn_dns/flow/PacketProtoDecoder.c      |  182 -
 external/badvpn_dns/flow/PacketProtoDecoder.h      |   96 -
 external/badvpn_dns/flow/PacketProtoEncoder.c      |  101 -
 external/badvpn_dns/flow/PacketProtoEncoder.h      |   80 -
 external/badvpn_dns/flow/PacketProtoFlow.c         |   82 -
 external/badvpn_dns/flow/PacketProtoFlow.h         |   83 -
 external/badvpn_dns/flow/PacketRecvBlocker.c       |   99 -
 external/badvpn_dns/flow/PacketRecvBlocker.h       |   90 -
 external/badvpn_dns/flow/PacketRecvConnector.c     |  123 -
 external/badvpn_dns/flow/PacketRecvConnector.h     |  102 -
 external/badvpn_dns/flow/PacketRecvInterface.c     |   56 -
 external/badvpn_dns/flow/PacketRecvInterface.h     |  170 -
 external/badvpn_dns/flow/PacketRouter.c            |  129 -
 external/badvpn_dns/flow/PacketRouter.h            |  126 -
 external/badvpn_dns/flow/PacketStreamSender.c      |  111 -
 external/badvpn_dns/flow/PacketStreamSender.h      |   83 -
 external/badvpn_dns/flow/RouteBuffer.c             |  256 -
 external/badvpn_dns/flow/RouteBuffer.h             |  139 -
 external/badvpn_dns/flow/SinglePacketBuffer.c      |   87 -
 external/badvpn_dns/flow/SinglePacketBuffer.h      |   75 -
 external/badvpn_dns/flow/SinglePacketSender.c      |   72 -
 external/badvpn_dns/flow/SinglePacketSender.h      |   82 -
 external/badvpn_dns/flow/SingleStreamReceiver.c    |   82 -
 external/badvpn_dns/flow/SingleStreamReceiver.h    |   53 -
 external/badvpn_dns/flow/SingleStreamSender.c      |   82 -
 external/badvpn_dns/flow/SingleStreamSender.h      |   53 -
 external/badvpn_dns/flow/StreamPacketSender.c      |   90 -
 external/badvpn_dns/flow/StreamPacketSender.h      |   77 -
 external/badvpn_dns/flow/StreamPassConnector.c     |  120 -
 external/badvpn_dns/flow/StreamPassConnector.h     |   98 -
 external/badvpn_dns/flow/StreamPassInterface.c     |   56 -
 external/badvpn_dns/flow/StreamPassInterface.h     |  165 -
 external/badvpn_dns/flow/StreamRecvConnector.c     |  120 -
 external/badvpn_dns/flow/StreamRecvConnector.h     |   98 -
 external/badvpn_dns/flow/StreamRecvInterface.c     |   56 -
 external/badvpn_dns/flow/StreamRecvInterface.h     |  165 -
 external/badvpn_dns/flowextra/CMakeLists.txt       |    5 -
 external/badvpn_dns/flowextra/KeepaliveIO.c        |  112 -
 external/badvpn_dns/flowextra/KeepaliveIO.h        |   88 -
 .../flowextra/PacketPassInactivityMonitor.c        |  131 -
 .../flowextra/PacketPassInactivityMonitor.h        |  124 -
 external/badvpn_dns/generate_files                 |   51 -
 .../badvpn_dns/generated/NCDConfigParser_parse.c   | 1890 --------
 .../badvpn_dns/generated/NCDConfigParser_parse.h   |   22 -
 .../badvpn_dns/generated/NCDConfigParser_parse.out |  950 ----
 .../badvpn_dns/generated/NCDConfigParser_parse.y   |  718 ---
 external/badvpn_dns/generated/NCDValParser_parse.c | 1119 -----
 external/badvpn_dns/generated/NCDValParser_parse.h |    7 -
 .../badvpn_dns/generated/NCDValParser_parse.out    |  217 -
 external/badvpn_dns/generated/NCDValParser_parse.y |  202 -
 external/badvpn_dns/generated/bison_BPredicate.c   | 2168 ---------
 external/badvpn_dns/generated/bison_BPredicate.h   |  114 -
 .../badvpn_dns/generated/blog_channel_BArpProbe.h  |    4 -
 .../generated/blog_channel_BConnection.h           |    4 -
 .../generated/blog_channel_BDHCPClient.h           |    4 -
 .../generated/blog_channel_BDHCPClientCore.h       |    4 -
 .../badvpn_dns/generated/blog_channel_BDatagram.h  |    4 -
 .../generated/blog_channel_BEncryption.h           |    4 -
 .../generated/blog_channel_BInputProcess.h         |    4 -
 .../generated/blog_channel_BLockReactor.h          |    4 -
 .../badvpn_dns/generated/blog_channel_BNetwork.h   |    4 -
 .../badvpn_dns/generated/blog_channel_BPredicate.h |    4 -
 .../badvpn_dns/generated/blog_channel_BProcess.h   |    4 -
 .../badvpn_dns/generated/blog_channel_BReactor.h   |    4 -
 .../generated/blog_channel_BSSLConnection.h        |    4 -
 .../badvpn_dns/generated/blog_channel_BSignal.h    |    4 -
 .../generated/blog_channel_BSocksClient.h          |    4 -
 external/badvpn_dns/generated/blog_channel_BTap.h  |    4 -
 .../generated/blog_channel_BThreadSignal.h         |    4 -
 .../generated/blog_channel_BThreadWork.h           |    4 -
 external/badvpn_dns/generated/blog_channel_BTime.h |    4 -
 .../generated/blog_channel_BUnixSignal.h           |    4 -
 .../badvpn_dns/generated/blog_channel_DPReceive.h  |    4 -
 .../badvpn_dns/generated/blog_channel_DPRelay.h    |    4 -
 .../badvpn_dns/generated/blog_channel_DataProto.h  |    4 -
 .../generated/blog_channel_DatagramPeerIO.h        |    4 -
 .../blog_channel_FragmentProtoAssembler.h          |    4 -
 .../generated/blog_channel_FrameDecider.h          |    4 -
 .../badvpn_dns/generated/blog_channel_LineBuffer.h |    4 -
 .../badvpn_dns/generated/blog_channel_Listener.h   |    4 -
 .../generated/blog_channel_NCDBuildProgram.h       |    4 -
 .../generated/blog_channel_NCDConfigParser.h       |    4 -
 .../generated/blog_channel_NCDConfigTokenizer.h    |    4 -
 .../generated/blog_channel_NCDIfConfig.h           |    4 -
 .../generated/blog_channel_NCDInterfaceMonitor.h   |    4 -
 .../generated/blog_channel_NCDModuleIndex.h        |    4 -
 .../generated/blog_channel_NCDModuleProcess.h      |    4 -
 .../generated/blog_channel_NCDPlaceholderDb.h      |    4 -
 .../badvpn_dns/generated/blog_channel_NCDRequest.h |    4 -
 .../generated/blog_channel_NCDRequestClient.h      |    4 -
 .../generated/blog_channel_NCDRfkillMonitor.h      |    4 -
 .../generated/blog_channel_NCDUdevCache.h          |    4 -
 .../generated/blog_channel_NCDUdevManager.h        |    4 -
 .../generated/blog_channel_NCDUdevMonitor.h        |    4 -
 .../generated/blog_channel_NCDUdevMonitorParser.h  |    4 -
 .../badvpn_dns/generated/blog_channel_NCDVal.h     |    4 -
 .../generated/blog_channel_NCDValGenerator.h       |    4 -
 .../generated/blog_channel_NCDValParser.h          |    4 -
 .../generated/blog_channel_PRStreamSink.h          |    4 -
 .../generated/blog_channel_PRStreamSource.h        |    4 -
 .../generated/blog_channel_PacketProtoDecoder.h    |    4 -
 .../generated/blog_channel_PasswordListener.h      |    4 -
 .../badvpn_dns/generated/blog_channel_PeerChat.h   |    4 -
 .../generated/blog_channel_SPProtoDecoder.h        |    4 -
 .../generated/blog_channel_ServerConnection.h      |    4 -
 .../generated/blog_channel_SocksUdpGwClient.h      |    4 -
 .../generated/blog_channel_StreamPeerIO.h          |    4 -
 .../generated/blog_channel_UdpGwClient.h           |    4 -
 external/badvpn_dns/generated/blog_channel_addr.h  |    4 -
 .../badvpn_dns/generated/blog_channel_client.h     |    4 -
 .../generated/blog_channel_dostest_attacker.h      |    4 -
 .../generated/blog_channel_dostest_server.h        |    4 -
 .../badvpn_dns/generated/blog_channel_flooder.h    |    4 -
 external/badvpn_dns/generated/blog_channel_lwip.h  |    4 -
 external/badvpn_dns/generated/blog_channel_ncd.h   |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_alias.h  |    4 -
 .../generated/blog_channel_ncd_arithmetic.h        |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_assert.h |    4 -
 .../generated/blog_channel_ncd_backtrack.h         |    4 -
 .../generated/blog_channel_ncd_blocker.h           |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_buffer.h |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_call2.h  |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_choose.h |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_concat.h |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_daemon.h |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_depend.h |    4 -
 .../generated/blog_channel_ncd_depend_scope.h      |    4 -
 .../generated/blog_channel_ncd_dynamic_depend.h    |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_exit.h   |    4 -
 .../generated/blog_channel_ncd_explode.h           |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_file.h   |    4 -
 .../generated/blog_channel_ncd_file_open.h         |    4 -
 .../generated/blog_channel_ncd_foreach.h           |    4 -
 .../generated/blog_channel_ncd_from_string.h       |    4 -
 .../generated/blog_channel_ncd_getargs.h           |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_getenv.h |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_if.h     |    4 -
 .../generated/blog_channel_ncd_imperative.h        |    4 -
 .../generated/blog_channel_ncd_implode.h           |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_index.h  |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_list.h   |    4 -
 .../generated/blog_channel_ncd_load_module.h       |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_log.h    |    4 -
 .../generated/blog_channel_ncd_log_msg.h           |    4 -
 .../generated/blog_channel_ncd_logical.h           |    4 -
 .../generated/blog_channel_ncd_multidepend.h       |    4 -
 .../blog_channel_ncd_net_backend_badvpn.h          |    4 -
 .../blog_channel_ncd_net_backend_rfkill.h          |    4 -
 .../blog_channel_ncd_net_backend_waitdevice.h      |    4 -
 .../blog_channel_ncd_net_backend_waitlink.h        |    4 -
 .../blog_channel_ncd_net_backend_wpa_supplicant.h  |    4 -
 .../generated/blog_channel_ncd_net_dns.h           |    4 -
 .../generated/blog_channel_ncd_net_iptables.h      |    4 -
 .../generated/blog_channel_ncd_net_ipv4_addr.h     |    4 -
 .../blog_channel_ncd_net_ipv4_addr_in_network.h    |    4 -
 .../blog_channel_ncd_net_ipv4_arp_probe.h          |    4 -
 .../generated/blog_channel_ncd_net_ipv4_dhcp.h     |    4 -
 .../generated/blog_channel_ncd_net_ipv4_route.h    |    4 -
 .../generated/blog_channel_ncd_net_ipv6_addr.h     |    4 -
 .../blog_channel_ncd_net_ipv6_addr_in_network.h    |    4 -
 .../generated/blog_channel_ncd_net_ipv6_route.h    |    4 -
 .../blog_channel_ncd_net_ipv6_wait_dynamic_addr.h  |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_net_up.h |    4 -
 .../blog_channel_ncd_net_watch_interfaces.h        |    4 -
 .../generated/blog_channel_ncd_netmask.h           |    4 -
 .../generated/blog_channel_ncd_ondemand.h          |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_parse.h  |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_print.h  |    4 -
 .../generated/blog_channel_ncd_process_manager.h   |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_reboot.h |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_ref.h    |    4 -
 .../generated/blog_channel_ncd_regex_match.h       |    4 -
 .../generated/blog_channel_ncd_request.h           |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_run.h    |    4 -
 .../generated/blog_channel_ncd_runonce.h           |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_sleep.h  |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_socket.h |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_spawn.h  |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_strcmp.h |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_substr.h |    4 -
 .../generated/blog_channel_ncd_sys_evdev.h         |    4 -
 .../blog_channel_ncd_sys_request_client.h          |    4 -
 .../blog_channel_ncd_sys_request_server.h          |    4 -
 .../generated/blog_channel_ncd_sys_start_process.h |    4 -
 .../blog_channel_ncd_sys_watch_directory.h         |    4 -
 .../generated/blog_channel_ncd_sys_watch_input.h   |    4 -
 .../generated/blog_channel_ncd_sys_watch_usb.h     |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_timer.h  |    4 -
 .../generated/blog_channel_ncd_to_string.h         |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_try.h    |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_value.h  |    4 -
 .../generated/blog_channel_ncd_valuemetic.h        |    4 -
 .../badvpn_dns/generated/blog_channel_ncd_var.h    |    4 -
 .../badvpn_dns/generated/blog_channel_nsskey.h     |    4 -
 .../badvpn_dns/generated/blog_channel_server.h     |    4 -
 .../badvpn_dns/generated/blog_channel_tun2socks.h  |    4 -
 external/badvpn_dns/generated/blog_channel_udpgw.h |    4 -
 .../badvpn_dns/generated/blog_channels_defines.h   |  146 -
 external/badvpn_dns/generated/blog_channels_list.h |  145 -
 external/badvpn_dns/generated/bproto_addr.h        |  675 ---
 external/badvpn_dns/generated/bproto_bproto_test.h | 1029 ----
 external/badvpn_dns/generated/bproto_msgproto.h    | 2122 ---------
 external/badvpn_dns/generated/flex_BPredicate.c    | 2143 ---------
 external/badvpn_dns/generated/flex_BPredicate.h    |  350 --
 external/badvpn_dns/lemon/lemon.c                  | 4889 --------------------
 external/badvpn_dns/lemon/lempar.c                 |  842 ----
 external/badvpn_dns/lime/HOWTO                     |   70 -
 external/badvpn_dns/lime/flex_token_stream.php     |   34 -
 external/badvpn_dns/lime/lemon.c                   | 4588 ------------------
 external/badvpn_dns/lime/lime.bootstrap            |   31 -
 external/badvpn_dns/lime/lime.php                  |  910 ----
 external/badvpn_dns/lime/lime_scan_tokens.l        |  121 -
 external/badvpn_dns/lime/metagrammar               |   58 -
 external/badvpn_dns/lime/parse_engine.php          |  252 -
 external/badvpn_dns/lime/set.so.php                |   29 -
 external/badvpn_dns/lwip/CHANGELOG                 | 3396 --------------
 external/badvpn_dns/lwip/CMakeLists.txt            |   27 -
 external/badvpn_dns/lwip/COPYING                   |   33 -
 external/badvpn_dns/lwip/FILES                     |    4 -
 external/badvpn_dns/lwip/README                    |   89 -
 external/badvpn_dns/lwip/UPGRADING                 |  144 -
 external/badvpn_dns/lwip/custom/arch/cc.h          |   96 -
 external/badvpn_dns/lwip/custom/arch/perf.h        |   36 -
 external/badvpn_dns/lwip/custom/lwipopts.h         |   70 -
 external/badvpn_dns/lwip/custom/sys.c              |   37 -
 external/badvpn_dns/lwip/doc/FILES                 |    6 -
 external/badvpn_dns/lwip/doc/contrib.txt           |   63 -
 external/badvpn_dns/lwip/doc/rawapi.txt            |  511 --
 external/badvpn_dns/lwip/doc/savannah.txt          |  135 -
 external/badvpn_dns/lwip/doc/snmp_agent.txt        |  181 -
 external/badvpn_dns/lwip/doc/sys_arch.txt          |  267 --
 external/badvpn_dns/lwip/lwip-base-version         |    1 -
 external/badvpn_dns/lwip/src/FILES                 |   13 -
 external/badvpn_dns/lwip/src/api/api_lib.c         |  788 ----
 external/badvpn_dns/lwip/src/api/api_msg.c         | 1610 -------
 external/badvpn_dns/lwip/src/api/err.c             |   75 -
 external/badvpn_dns/lwip/src/api/netbuf.c          |  245 -
 external/badvpn_dns/lwip/src/api/netdb.c           |  353 --
 external/badvpn_dns/lwip/src/api/netifapi.c        |  160 -
 external/badvpn_dns/lwip/src/api/sockets.c         | 2555 ----------
 external/badvpn_dns/lwip/src/api/tcpip.c           |  492 --
 external/badvpn_dns/lwip/src/core/def.c            |  108 -
 external/badvpn_dns/lwip/src/core/dhcp.c           | 1771 -------
 external/badvpn_dns/lwip/src/core/dns.c            |  988 ----
 external/badvpn_dns/lwip/src/core/inet_chksum.c    |  545 ---
 external/badvpn_dns/lwip/src/core/init.c           |  345 --
 external/badvpn_dns/lwip/src/core/ipv4/autoip.c    |  528 ---
 external/badvpn_dns/lwip/src/core/ipv4/icmp.c      |  338 --
 external/badvpn_dns/lwip/src/core/ipv4/igmp.c      |  805 ----
 external/badvpn_dns/lwip/src/core/ipv4/ip4.c       |  924 ----
 external/badvpn_dns/lwip/src/core/ipv4/ip4_addr.c  |  312 --
 external/badvpn_dns/lwip/src/core/ipv4/ip_frag.c   |  863 ----
 external/badvpn_dns/lwip/src/core/ipv6/README      |    1 -
 external/badvpn_dns/lwip/src/core/ipv6/dhcp6.c     |   50 -
 external/badvpn_dns/lwip/src/core/ipv6/ethip6.c    |  193 -
 external/badvpn_dns/lwip/src/core/ipv6/icmp6.c     |  337 --
 external/badvpn_dns/lwip/src/core/ipv6/inet6.c     |   51 -
 external/badvpn_dns/lwip/src/core/ipv6/ip6.c       | 1034 -----
 external/badvpn_dns/lwip/src/core/ipv6/ip6_addr.c  |  251 -
 external/badvpn_dns/lwip/src/core/ipv6/ip6_frag.c  |  697 ---
 external/badvpn_dns/lwip/src/core/ipv6/mld6.c      |  580 ---
 external/badvpn_dns/lwip/src/core/ipv6/nd6.c       | 1787 -------
 external/badvpn_dns/lwip/src/core/mem.c            |  659 ---
 external/badvpn_dns/lwip/src/core/memp.c           |  485 --
 external/badvpn_dns/lwip/src/core/netif.c          |  918 ----
 external/badvpn_dns/lwip/src/core/pbuf.c           | 1179 -----
 external/badvpn_dns/lwip/src/core/raw.c            |  422 --
 external/badvpn_dns/lwip/src/core/snmp/asn1_dec.c  |  657 ---
 external/badvpn_dns/lwip/src/core/snmp/asn1_enc.c  |  611 ---
 external/badvpn_dns/lwip/src/core/snmp/mib2.c      | 4146 -----------------
 .../badvpn_dns/lwip/src/core/snmp/mib_structs.c    | 1174 -----
 external/badvpn_dns/lwip/src/core/snmp/msg_in.c    | 1453 ------
 external/badvpn_dns/lwip/src/core/snmp/msg_out.c   |  678 ---
 external/badvpn_dns/lwip/src/core/stats.c          |  181 -
 external/badvpn_dns/lwip/src/core/sys.c            |   68 -
 external/badvpn_dns/lwip/src/core/tcp.c            | 1852 --------
 external/badvpn_dns/lwip/src/core/tcp_in.c         | 1666 -------
 external/badvpn_dns/lwip/src/core/tcp_out.c        | 1499 ------
 external/badvpn_dns/lwip/src/core/timers.c         |  546 ---
 external/badvpn_dns/lwip/src/core/udp.c            | 1151 -----
 .../badvpn_dns/lwip/src/include/ipv4/lwip/autoip.h |  118 -
 .../badvpn_dns/lwip/src/include/ipv4/lwip/icmp.h   |  125 -
 .../badvpn_dns/lwip/src/include/ipv4/lwip/igmp.h   |  106 -
 .../badvpn_dns/lwip/src/include/ipv4/lwip/inet.h   |  107 -
 .../badvpn_dns/lwip/src/include/ipv4/lwip/ip4.h    |  146 -
 .../lwip/src/include/ipv4/lwip/ip4_addr.h          |  244 -
 .../lwip/src/include/ipv4/lwip/ip_frag.h           |   91 -
 .../badvpn_dns/lwip/src/include/ipv6/lwip/dhcp6.h  |   58 -
 .../badvpn_dns/lwip/src/include/ipv6/lwip/ethip6.h |   68 -
 .../badvpn_dns/lwip/src/include/ipv6/lwip/icmp6.h  |  152 -
 .../badvpn_dns/lwip/src/include/ipv6/lwip/inet6.h  |   92 -
 .../badvpn_dns/lwip/src/include/ipv6/lwip/ip6.h    |  197 -
 .../lwip/src/include/ipv6/lwip/ip6_addr.h          |  286 --
 .../lwip/src/include/ipv6/lwip/ip6_frag.h          |  102 -
 .../badvpn_dns/lwip/src/include/ipv6/lwip/mld6.h   |  118 -
 .../badvpn_dns/lwip/src/include/ipv6/lwip/nd6.h    |  369 --
 external/badvpn_dns/lwip/src/include/lwip/api.h    |  338 --
 .../badvpn_dns/lwip/src/include/lwip/api_msg.h     |  177 -
 external/badvpn_dns/lwip/src/include/lwip/arch.h   |  217 -
 external/badvpn_dns/lwip/src/include/lwip/debug.h  |   99 -
 external/badvpn_dns/lwip/src/include/lwip/def.h    |  123 -
 external/badvpn_dns/lwip/src/include/lwip/dhcp.h   |  242 -
 external/badvpn_dns/lwip/src/include/lwip/dns.h    |  124 -
 external/badvpn_dns/lwip/src/include/lwip/err.h    |   85 -
 .../badvpn_dns/lwip/src/include/lwip/inet_chksum.h |  112 -
 external/badvpn_dns/lwip/src/include/lwip/init.h   |   72 -
 external/badvpn_dns/lwip/src/include/lwip/ip.h     |  254 -
 .../badvpn_dns/lwip/src/include/lwip/ip_addr.h     |  130 -
 external/badvpn_dns/lwip/src/include/lwip/mem.h    |  123 -
 external/badvpn_dns/lwip/src/include/lwip/memp.h   |  116 -
 .../badvpn_dns/lwip/src/include/lwip/memp_std.h    |  135 -
 external/badvpn_dns/lwip/src/include/lwip/netbuf.h |  112 -
 external/badvpn_dns/lwip/src/include/lwip/netdb.h  |  124 -
 external/badvpn_dns/lwip/src/include/lwip/netif.h  |  393 --
 .../badvpn_dns/lwip/src/include/lwip/netifapi.h    |  108 -
 external/badvpn_dns/lwip/src/include/lwip/opt.h    | 2417 ----------
 external/badvpn_dns/lwip/src/include/lwip/pbuf.h   |  185 -
 external/badvpn_dns/lwip/src/include/lwip/raw.h    |  131 -
 external/badvpn_dns/lwip/src/include/lwip/sio.h    |  141 -
 external/badvpn_dns/lwip/src/include/lwip/snmp.h   |  367 --
 .../badvpn_dns/lwip/src/include/lwip/snmp_asn1.h   |  101 -
 .../badvpn_dns/lwip/src/include/lwip/snmp_msg.h    |  315 --
 .../lwip/src/include/lwip/snmp_structs.h           |  268 --
 .../badvpn_dns/lwip/src/include/lwip/sockets.h     |  411 --
 external/badvpn_dns/lwip/src/include/lwip/stats.h  |  347 --
 external/badvpn_dns/lwip/src/include/lwip/sys.h    |  336 --
 external/badvpn_dns/lwip/src/include/lwip/tcp.h    |  400 --
 .../badvpn_dns/lwip/src/include/lwip/tcp_impl.h    |  508 --
 external/badvpn_dns/lwip/src/include/lwip/tcpip.h  |  179 -
 external/badvpn_dns/lwip/src/include/lwip/timers.h |  100 -
 external/badvpn_dns/lwip/src/include/lwip/udp.h    |  215 -
 .../badvpn_dns/lwip/src/include/netif/etharp.h     |  223 -
 .../badvpn_dns/lwip/src/include/netif/ppp_oe.h     |  190 -
 .../badvpn_dns/lwip/src/include/netif/slipif.h     |   81 -
 external/badvpn_dns/lwip/src/include/posix/netdb.h |   33 -
 .../badvpn_dns/lwip/src/include/posix/sys/socket.h |   33 -
 external/badvpn_dns/lwip/src/netif/FILES           |   29 -
 external/badvpn_dns/lwip/src/netif/etharp.c        | 1413 ------
 external/badvpn_dns/lwip/src/netif/ethernetif.c    |  322 --
 external/badvpn_dns/lwip/src/netif/ppp/auth.c      | 1334 ------
 external/badvpn_dns/lwip/src/netif/ppp/auth.h      |  111 -
 external/badvpn_dns/lwip/src/netif/ppp/chap.c      |  908 ----
 external/badvpn_dns/lwip/src/netif/ppp/chap.h      |  150 -
 external/badvpn_dns/lwip/src/netif/ppp/chpms.c     |  396 --
 external/badvpn_dns/lwip/src/netif/ppp/chpms.h     |   64 -
 external/badvpn_dns/lwip/src/netif/ppp/fsm.c       |  890 ----
 external/badvpn_dns/lwip/src/netif/ppp/fsm.h       |  157 -
 external/badvpn_dns/lwip/src/netif/ppp/ipcp.c      | 1411 ------
 external/badvpn_dns/lwip/src/netif/ppp/ipcp.h      |  106 -
 external/badvpn_dns/lwip/src/netif/ppp/lcp.c       | 2066 ---------
 external/badvpn_dns/lwip/src/netif/ppp/lcp.h       |  151 -
 external/badvpn_dns/lwip/src/netif/ppp/magic.c     |   80 -
 external/badvpn_dns/lwip/src/netif/ppp/magic.h     |   63 -
 external/badvpn_dns/lwip/src/netif/ppp/md5.c       |  320 --
 external/badvpn_dns/lwip/src/netif/ppp/md5.h       |   55 -
 external/badvpn_dns/lwip/src/netif/ppp/pap.c       |  628 ---
 external/badvpn_dns/lwip/src/netif/ppp/pap.h       |  118 -
 external/badvpn_dns/lwip/src/netif/ppp/ppp.c       | 2052 --------
 external/badvpn_dns/lwip/src/netif/ppp/ppp.h       |  201 -
 external/badvpn_dns/lwip/src/netif/ppp/ppp_impl.h  |  363 --
 external/badvpn_dns/lwip/src/netif/ppp/ppp_oe.c    | 1132 -----
 external/badvpn_dns/lwip/src/netif/ppp/pppdebug.h  |   73 -
 external/badvpn_dns/lwip/src/netif/ppp/randm.c     |  249 -
 external/badvpn_dns/lwip/src/netif/ppp/randm.h     |   81 -
 external/badvpn_dns/lwip/src/netif/ppp/readme.txt  |   21 -
 external/badvpn_dns/lwip/src/netif/ppp/vj.c        |  652 ---
 external/badvpn_dns/lwip/src/netif/ppp/vj.h        |  156 -
 external/badvpn_dns/lwip/src/netif/slipif.c        |  546 ---
 external/badvpn_dns/lwip/test/unit/core/test_mem.c |   73 -
 external/badvpn_dns/lwip/test/unit/core/test_mem.h |    8 -
 .../badvpn_dns/lwip/test/unit/core/test_pbuf.c     |   73 -
 .../badvpn_dns/lwip/test/unit/core/test_pbuf.h     |    8 -
 .../badvpn_dns/lwip/test/unit/dhcp/test_dhcp.c     |  916 ----
 .../badvpn_dns/lwip/test/unit/dhcp/test_dhcp.h     |    8 -
 .../badvpn_dns/lwip/test/unit/etharp/test_etharp.c |  262 --
 .../badvpn_dns/lwip/test/unit/etharp/test_etharp.h |    8 -
 external/badvpn_dns/lwip/test/unit/lwip_check.h    |   37 -
 .../badvpn_dns/lwip/test/unit/lwip_unittests.c     |   49 -
 external/badvpn_dns/lwip/test/unit/lwipopts.h      |   53 -
 .../badvpn_dns/lwip/test/unit/tcp/tcp_helper.c     |  303 --
 .../badvpn_dns/lwip/test/unit/tcp/tcp_helper.h     |   52 -
 external/badvpn_dns/lwip/test/unit/tcp/test_tcp.c  |  671 ---
 external/badvpn_dns/lwip/test/unit/tcp/test_tcp.h  |    8 -
 .../badvpn_dns/lwip/test/unit/tcp/test_tcp_oos.c   |  958 ----
 .../badvpn_dns/lwip/test/unit/tcp/test_tcp_oos.h   |    8 -
 external/badvpn_dns/lwip/test/unit/udp/test_udp.c  |   68 -
 external/badvpn_dns/lwip/test/unit/udp/test_udp.h  |    8 -
 external/badvpn_dns/misc/BRefTarget.h              |  114 -
 external/badvpn_dns/misc/Utf16Decoder.h            |  113 -
 external/badvpn_dns/misc/Utf16Encoder.h            |   67 -
 external/badvpn_dns/misc/Utf8Decoder.h             |  143 -
 external/badvpn_dns/misc/Utf8Encoder.h             |   81 -
 external/badvpn_dns/misc/arp_proto.h               |   60 -
 external/badvpn_dns/misc/array_length.h            |   35 -
 external/badvpn_dns/misc/balign.h                  |   76 -
 external/badvpn_dns/misc/balloc.h                  |  248 -
 external/badvpn_dns/misc/blimits.h                 |   60 -
 external/badvpn_dns/misc/bsize.h                   |  117 -
 external/badvpn_dns/misc/bsort.h                   |   69 -
 external/badvpn_dns/misc/bstring.h                 |  140 -
 external/badvpn_dns/misc/byteorder.h               |  196 -
 external/badvpn_dns/misc/cmdline.h                 |  181 -
 external/badvpn_dns/misc/compare.h                 |   37 -
 external/badvpn_dns/misc/concat_strings.h          |   85 -
 external/badvpn_dns/misc/cstring.h                 |  347 --
 external/badvpn_dns/misc/dead.h                    |  134 -
 external/badvpn_dns/misc/debug.h                   |  142 -
 external/badvpn_dns/misc/debugcounter.h            |  118 -
 external/badvpn_dns/misc/debugerror.h              |   90 -
 external/badvpn_dns/misc/dhcp_proto.h              |  131 -
 external/badvpn_dns/misc/ethernet_proto.h          |   52 -
 external/badvpn_dns/misc/exparray.h                |  101 -
 external/badvpn_dns/misc/expstring.h               |  161 -
 external/badvpn_dns/misc/find_char.h               |   58 -
 external/badvpn_dns/misc/find_program.h            |  103 -
 external/badvpn_dns/misc/get_iface_info.h          |  110 -
 external/badvpn_dns/misc/grow_array.h              |  139 -
 external/badvpn_dns/misc/hashfun.h                 |   60 -
 external/badvpn_dns/misc/igmp_proto.h              |   97 -
 external/badvpn_dns/misc/ipaddr.h                  |  218 -
 external/badvpn_dns/misc/ipaddr6.h                 |  400 --
 external/badvpn_dns/misc/ipv4_proto.h              |  145 -
 external/badvpn_dns/misc/ipv6_proto.h              |   86 -
 external/badvpn_dns/misc/loggers_string.h          |   43 -
 external/badvpn_dns/misc/loglevel.h                |   80 -
 external/badvpn_dns/misc/maxalign.h                |   53 -
 external/badvpn_dns/misc/merge.h                   |   36 -
 external/badvpn_dns/misc/minmax.h                  |   56 -
 external/badvpn_dns/misc/modadd.h                  |   59 -
 external/badvpn_dns/misc/mswsock.h                 |  229 -
 external/badvpn_dns/misc/nonblocking.h             |   51 -
 external/badvpn_dns/misc/nsskey.h                  |  118 -
 external/badvpn_dns/misc/offset.h                  |   51 -
 external/badvpn_dns/misc/open_standard_streams.h   |   54 -
 external/badvpn_dns/misc/overflow.h                |   66 -
 external/badvpn_dns/misc/packed.h                  |   51 -
 external/badvpn_dns/misc/parse_number.h            |  304 --
 external/badvpn_dns/misc/print_macros.h            |   98 -
 external/badvpn_dns/misc/read_file.h               |   98 -
 external/badvpn_dns/misc/read_write_int.h          |  181 -
 external/badvpn_dns/misc/socks_proto.h             |  118 -
 external/badvpn_dns/misc/sslsocket.h               |   48 -
 external/badvpn_dns/misc/stdbuf_cmdline.h          |   92 -
 external/badvpn_dns/misc/strdup.h                  |   86 -
 external/badvpn_dns/misc/string_begins_with.h      |   96 -
 external/badvpn_dns/misc/substring.h               |   81 -
 external/badvpn_dns/misc/udp_proto.h               |  170 -
 external/badvpn_dns/misc/unicode_funcs.h           |  232 -
 external/badvpn_dns/misc/version.h                 |   41 -
 external/badvpn_dns/misc/write_file.h              |  104 -
 external/badvpn_dns/ncd-request/CMakeLists.txt     |    9 -
 external/badvpn_dns/ncd-request/ncd-request.c      |  224 -
 external/badvpn_dns/ncd/CMakeLists.txt             |  211 -
 external/badvpn_dns/ncd/NCDAst.c                   | 1022 ----
 external/badvpn_dns/ncd/NCDAst.h                   |  237 -
 external/badvpn_dns/ncd/NCDBuildProgram.c          |  316 --
 external/badvpn_dns/ncd/NCDBuildProgram.h          |   49 -
 external/badvpn_dns/ncd/NCDConfigParser.c          |  214 -
 external/badvpn_dns/ncd/NCDConfigParser.h          |   40 -
 external/badvpn_dns/ncd/NCDConfigParser_parse.y    |  718 ---
 external/badvpn_dns/ncd/NCDConfigTokenizer.c       |  321 --
 external/badvpn_dns/ncd/NCDConfigTokenizer.h       |   64 -
 external/badvpn_dns/ncd/NCDInterpProcess.c         |  497 --
 external/badvpn_dns/ncd/NCDInterpProcess.h         |  100 -
 external/badvpn_dns/ncd/NCDInterpProg.c            |  140 -
 external/badvpn_dns/ncd/NCDInterpProg.h            |   63 -
 external/badvpn_dns/ncd/NCDInterpProg_hash.h       |   12 -
 external/badvpn_dns/ncd/NCDInterpreter.c           | 1356 ------
 external/badvpn_dns/ncd/NCDInterpreter.h           |  156 -
 external/badvpn_dns/ncd/NCDMethodIndex.c           |  272 --
 external/badvpn_dns/ncd/NCDMethodIndex.h           |  135 -
 external/badvpn_dns/ncd/NCDMethodIndex_hash.h      |   12 -
 external/badvpn_dns/ncd/NCDModule.c                |  625 ---
 external/badvpn_dns/ncd/NCDModule.h                | 1011 ----
 external/badvpn_dns/ncd/NCDModuleIndex.c           |  372 --
 external/badvpn_dns/ncd/NCDModuleIndex.h           |   86 -
 external/badvpn_dns/ncd/NCDModuleIndex_mhash.h     |   12 -
 external/badvpn_dns/ncd/NCDObject.c                |   40 -
 external/badvpn_dns/ncd/NCDObject.h                |  356 --
 external/badvpn_dns/ncd/NCDPlaceholderDb.c         |  127 -
 external/badvpn_dns/ncd/NCDPlaceholderDb.h         |   95 -
 external/badvpn_dns/ncd/NCDStringIndex.c           |  262 --
 external/badvpn_dns/ncd/NCDStringIndex.h           |   83 -
 external/badvpn_dns/ncd/NCDStringIndex_hash.h      |   13 -
 external/badvpn_dns/ncd/NCDSugar.c                 |  253 -
 external/badvpn_dns/ncd/NCDSugar.h                 |   38 -
 external/badvpn_dns/ncd/NCDVal.c                   | 2065 ---------
 external/badvpn_dns/ncd/NCDVal.h                   |  857 ----
 external/badvpn_dns/ncd/NCDValCons.c               |  283 --
 external/badvpn_dns/ncd/NCDValCons.h               |  176 -
 external/badvpn_dns/ncd/NCDValGenerator.c          |  193 -
 external/badvpn_dns/ncd/NCDValGenerator.h          |   40 -
 external/badvpn_dns/ncd/NCDValParser.c             |  225 -
 external/badvpn_dns/ncd/NCDValParser.h             |   50 -
 external/badvpn_dns/ncd/NCDValParser_parse.y       |  202 -
 external/badvpn_dns/ncd/NCDVal_maptree.h           |   15 -
 external/badvpn_dns/ncd/README                     |  386 --
 external/badvpn_dns/ncd/emncd.c                    |  137 -
 external/badvpn_dns/ncd/emncd.html                 |  320 --
 external/badvpn_dns/ncd/examples/dbus_start.ncd    |   82 -
 .../badvpn_dns/ncd/examples/dhcpd.conf.template    |   11 -
 .../badvpn_dns/ncd/examples/directory_updater.ncd  |   72 -
 external/badvpn_dns/ncd/examples/events.ncd        |  101 -
 .../ncd/examples/igmpproxy.conf.template           |   10 -
 .../badvpn_dns/ncd/examples/make_dhcp_config.ncd   |   27 -
 .../ncd/examples/make_igmpproxy_config.ncd         |   53 -
 external/badvpn_dns/ncd/examples/network.ncd       |  123 -
 external/badvpn_dns/ncd/examples/onoff_server.ncdi |   82 -
 .../badvpn_dns/ncd/examples/onoff_server_test.ncd  |   20 -
 external/badvpn_dns/ncd/examples/router/README     |   36 -
 .../ncd/examples/router/add-port-forwarding        |   43 -
 .../ncd/examples/router/dhcp_server.ncdi           |   60 -
 .../ncd/examples/router/list-port-forwardings      |   61 -
 external/badvpn_dns/ncd/examples/router/ncd.conf   |    6 -
 .../badvpn_dns/ncd/examples/router/network.ncdi    |  356 --
 .../examples/router/network_control_server.ncdi    |   96 -
 .../ncd/examples/router/port_forwarding.ncdi       |  170 -
 external/badvpn_dns/ncd/examples/router/pppoe.ncdi |  296 --
 .../ncd/examples/router/remove-port-forwarding     |   43 -
 .../badvpn_dns/ncd/examples/router/unbound.ncdi    |   42 -
 .../badvpn_dns/ncd/examples/tcp_echo_client.ncd    |   35 -
 .../badvpn_dns/ncd/examples/tcp_echo_server.ncd    |   40 -
 external/badvpn_dns/ncd/extra/BEventLock.c         |  146 -
 external/badvpn_dns/ncd/extra/BEventLock.h         |  127 -
 external/badvpn_dns/ncd/extra/NCDBProcessOpts.c    |  154 -
 external/badvpn_dns/ncd/extra/NCDBProcessOpts.h    |   54 -
 external/badvpn_dns/ncd/extra/NCDBuf.c             |  123 -
 external/badvpn_dns/ncd/extra/NCDBuf.h             |   61 -
 external/badvpn_dns/ncd/extra/NCDIfConfig.c        |  483 --
 external/badvpn_dns/ncd/extra/NCDIfConfig.h        |   70 -
 .../badvpn_dns/ncd/extra/NCDInterfaceMonitor.c     |  446 --
 .../badvpn_dns/ncd/extra/NCDInterfaceMonitor.h     |  160 -
 external/badvpn_dns/ncd/extra/NCDRequestClient.c   |  647 ---
 external/badvpn_dns/ncd/extra/NCDRequestClient.h   |  111 -
 external/badvpn_dns/ncd/extra/NCDRfkillMonitor.c   |  117 -
 external/badvpn_dns/ncd/extra/NCDRfkillMonitor.h   |   53 -
 external/badvpn_dns/ncd/extra/address_utils.h      |  280 --
 external/badvpn_dns/ncd/extra/build_cmdline.c      |  111 -
 external/badvpn_dns/ncd/extra/build_cmdline.h      |   38 -
 external/badvpn_dns/ncd/extra/make_fast_names.h    |  154 -
 external/badvpn_dns/ncd/extra/value_utils.h        |  174 -
 external/badvpn_dns/ncd/include_linux_input.c      |    1 -
 external/badvpn_dns/ncd/make_name_indices.h        |  104 -
 external/badvpn_dns/ncd/modules/alias.c            |  148 -
 external/badvpn_dns/ncd/modules/arithmetic.c       |  404 --
 external/badvpn_dns/ncd/modules/assert.c           |  105 -
 external/badvpn_dns/ncd/modules/backtrack.c        |  103 -
 external/badvpn_dns/ncd/modules/blocker.c          |  353 --
 external/badvpn_dns/ncd/modules/buffer.c           |  619 ---
 .../badvpn_dns/ncd/modules/buffer_chunks_tree.h    |    9 -
 external/badvpn_dns/ncd/modules/call2.c            |  498 --
 external/badvpn_dns/ncd/modules/choose.c           |  145 -
 external/badvpn_dns/ncd/modules/command_template.c |  218 -
 external/badvpn_dns/ncd/modules/command_template.h |   62 -
 external/badvpn_dns/ncd/modules/concat.c           |  189 -
 external/badvpn_dns/ncd/modules/daemon.c           |  296 --
 external/badvpn_dns/ncd/modules/depend.c           |  452 --
 external/badvpn_dns/ncd/modules/depend_scope.c     |  466 --
 external/badvpn_dns/ncd/modules/dynamic_depend.c   |  548 ---
 external/badvpn_dns/ncd/modules/event_template.c   |  184 -
 external/badvpn_dns/ncd/modules/event_template.h   |   64 -
 external/badvpn_dns/ncd/modules/exit.c             |   91 -
 external/badvpn_dns/ncd/modules/explode.c          |  232 -
 external/badvpn_dns/ncd/modules/file.c             |  350 --
 external/badvpn_dns/ncd/modules/file_open.c        |  585 ---
 external/badvpn_dns/ncd/modules/foreach.c          |  715 ---
 external/badvpn_dns/ncd/modules/from_string.c      |  125 -
 external/badvpn_dns/ncd/modules/getargs.c          |   98 -
 external/badvpn_dns/ncd/modules/getenv.c           |  153 -
 external/badvpn_dns/ncd/modules/if.c               |  103 -
 external/badvpn_dns/ncd/modules/imperative.c       |  324 --
 external/badvpn_dns/ncd/modules/implode.c          |  155 -
 external/badvpn_dns/ncd/modules/index.c            |  164 -
 external/badvpn_dns/ncd/modules/list.c             |  871 ----
 external/badvpn_dns/ncd/modules/load_module.c      |  313 --
 external/badvpn_dns/ncd/modules/log.c              |  285 --
 external/badvpn_dns/ncd/modules/logical.c          |  160 -
 external/badvpn_dns/ncd/modules/modules.h          |  210 -
 external/badvpn_dns/ncd/modules/multidepend.c      |  401 --
 .../badvpn_dns/ncd/modules/net_backend_badvpn.c    |  281 --
 .../badvpn_dns/ncd/modules/net_backend_rfkill.c    |  216 -
 .../ncd/modules/net_backend_waitdevice.c           |  187 -
 .../badvpn_dns/ncd/modules/net_backend_waitlink.c  |  155 -
 .../ncd/modules/net_backend_wpa_supplicant.c       |  573 ---
 external/badvpn_dns/ncd/modules/net_dns.c          |  434 --
 external/badvpn_dns/ncd/modules/net_iptables.c     |  749 ---
 external/badvpn_dns/ncd/modules/net_ipv4_addr.c    |  148 -
 .../ncd/modules/net_ipv4_addr_in_network.c         |  173 -
 .../badvpn_dns/ncd/modules/net_ipv4_arp_probe.c    |  212 -
 external/badvpn_dns/ncd/modules/net_ipv4_dhcp.c    |  351 --
 external/badvpn_dns/ncd/modules/net_ipv4_route.c   |  211 -
 external/badvpn_dns/ncd/modules/net_ipv6_addr.c    |  148 -
 .../ncd/modules/net_ipv6_addr_in_network.c         |  168 -
 external/badvpn_dns/ncd/modules/net_ipv6_route.c   |  213 -
 .../ncd/modules/net_ipv6_wait_dynamic_addr.c       |  201 -
 external/badvpn_dns/ncd/modules/net_up.c           |  119 -
 .../badvpn_dns/ncd/modules/net_watch_interfaces.c  |  474 --
 external/badvpn_dns/ncd/modules/netmask.c          |  263 --
 external/badvpn_dns/ncd/modules/ondemand.c         |  372 --
 external/badvpn_dns/ncd/modules/parse.c            |  392 --
 external/badvpn_dns/ncd/modules/print.c            |  207 -
 external/badvpn_dns/ncd/modules/process_manager.c  |  538 ---
 external/badvpn_dns/ncd/modules/reboot.c           |  103 -
 external/badvpn_dns/ncd/modules/ref.c              |  215 -
 external/badvpn_dns/ncd/modules/regex_match.c      |  369 --
 external/badvpn_dns/ncd/modules/run.c              |  187 -
 external/badvpn_dns/ncd/modules/runonce.c          |  331 --
 external/badvpn_dns/ncd/modules/sleep.c            |  178 -
 external/badvpn_dns/ncd/modules/socket.c           | 1057 -----
 external/badvpn_dns/ncd/modules/spawn.c            |  410 --
 external/badvpn_dns/ncd/modules/strcmp.c           |  107 -
 external/badvpn_dns/ncd/modules/substr.c           |  167 -
 external/badvpn_dns/ncd/modules/sys_evdev.c        |  348 --
 .../badvpn_dns/ncd/modules/sys_request_client.c    |  646 ---
 .../badvpn_dns/ncd/modules/sys_request_server.c    |  792 ----
 .../badvpn_dns/ncd/modules/sys_start_process.c     | 1266 -----
 .../badvpn_dns/ncd/modules/sys_watch_directory.c   |  425 --
 external/badvpn_dns/ncd/modules/sys_watch_input.c  |  455 --
 external/badvpn_dns/ncd/modules/sys_watch_usb.c    |  421 --
 external/badvpn_dns/ncd/modules/timer.c            |  146 -
 external/badvpn_dns/ncd/modules/to_string.c        |  116 -
 external/badvpn_dns/ncd/modules/try.c              |  302 --
 external/badvpn_dns/ncd/modules/value.c            | 2102 ---------
 external/badvpn_dns/ncd/modules/value_maptree.h    |   11 -
 external/badvpn_dns/ncd/modules/valuemetic.c       |  219 -
 external/badvpn_dns/ncd/modules/var.c              |  163 -
 external/badvpn_dns/ncd/ncd.c                      |  463 --
 external/badvpn_dns/ncd/ncd.h                      |   37 -
 external/badvpn_dns/ncd/parse_linux_input.sh       |   94 -
 external/badvpn_dns/ncd/static_strings.h           |   70 -
 external/badvpn_dns/ncd/tests/addr_in_network.ncd  |   60 -
 external/badvpn_dns/ncd/tests/alias.ncd            |   48 -
 external/badvpn_dns/ncd/tests/arithmetic.ncd       |   69 -
 external/badvpn_dns/ncd/tests/backtracking.ncd     |   31 -
 external/badvpn_dns/ncd/tests/buffer.ncd           |   54 -
 external/badvpn_dns/ncd/tests/call.ncd             |   18 -
 external/badvpn_dns/ncd/tests/concat.ncd           |   19 -
 external/badvpn_dns/ncd/tests/depend.ncd           |   64 -
 external/badvpn_dns/ncd/tests/depend_scope.ncd     |   31 -
 external/badvpn_dns/ncd/tests/escape_and_nulls.ncd |   38 -
 external/badvpn_dns/ncd/tests/explode.ncd          |   23 -
 external/badvpn_dns/ncd/tests/foreach.ncd          |   35 -
 external/badvpn_dns/ncd/tests/if.ncd               |   38 -
 external/badvpn_dns/ncd/tests/implode.ncd          |   15 -
 external/badvpn_dns/ncd/tests/include.ncd          |   16 -
 .../badvpn_dns/ncd/tests/include_included.ncdi     |    5 -
 .../badvpn_dns/ncd/tests/include_included2.ncdi    |    5 -
 external/badvpn_dns/ncd/tests/logical.ncd          |   46 -
 external/badvpn_dns/ncd/tests/multidepend.ncd      |   30 -
 external/badvpn_dns/ncd/tests/netmask.ncd          |   15 -
 external/badvpn_dns/ncd/tests/parse.ncd            |   85 -
 external/badvpn_dns/ncd/tests/process_manager.ncd  |  112 -
 external/badvpn_dns/ncd/tests/regex.ncd            |   48 -
 external/badvpn_dns/ncd/tests/run_tests            |   38 -
 external/badvpn_dns/ncd/tests/strings.ncd          |   47 -
 external/badvpn_dns/ncd/tests/substr.ncd           |   37 -
 external/badvpn_dns/ncd/tests/turing.ncd           |  138 -
 external/badvpn_dns/ncd/tests/value.ncd            |  258 --
 external/badvpn_dns/ncd/tests/value_substr.ncd     |   25 -
 external/badvpn_dns/nspr_support/BSSLConnection.c  | 1024 ----
 external/badvpn_dns/nspr_support/BSSLConnection.h  |  116 -
 external/badvpn_dns/nspr_support/CMakeLists.txt    |    5 -
 external/badvpn_dns/nspr_support/DummyPRFileDesc.c |  176 -
 external/badvpn_dns/nspr_support/DummyPRFileDesc.h |   61 -
 external/badvpn_dns/predicate/BPredicate.c         |  284 --
 external/badvpn_dns/predicate/BPredicate.h         |  177 -
 external/badvpn_dns/predicate/BPredicate.l         |   83 -
 external/badvpn_dns/predicate/BPredicate.y         |  345 --
 .../badvpn_dns/predicate/BPredicate_internal.h     |  154 -
 external/badvpn_dns/predicate/BPredicate_parser.h  |   47 -
 external/badvpn_dns/predicate/CMakeLists.txt       |    6 -
 .../badvpn_dns/predicate/LexMemoryBufferInput.h    |   86 -
 external/badvpn_dns/protocol/addr.bproto           |   11 -
 external/badvpn_dns/protocol/addr.h                |  207 -
 external/badvpn_dns/protocol/dataproto.h           |   91 -
 external/badvpn_dns/protocol/fragmentproto.h       |  100 -
 external/badvpn_dns/protocol/msgproto.bproto       |   43 -
 external/badvpn_dns/protocol/msgproto.h            |   76 -
 external/badvpn_dns/protocol/packetproto.h         |   68 -
 external/badvpn_dns/protocol/requestproto.h        |   50 -
 external/badvpn_dns/protocol/scproto.h             |  266 --
 external/badvpn_dns/protocol/spproto.h             |  195 -
 external/badvpn_dns/protocol/udpgw_proto.h         |   84 -
 external/badvpn_dns/random/BRandom2.c              |   90 -
 external/badvpn_dns/random/BRandom2.h              |   50 -
 external/badvpn_dns/random/CMakeLists.txt          |    1 -
 external/badvpn_dns/scripts/cmake                  |    8 -
 external/badvpn_dns/scripts/copy_nss               |   23 -
 external/badvpn_dns/scripts/toolchain.cmake        |    6 -
 external/badvpn_dns/security/BEncryption.c         |  240 -
 external/badvpn_dns/security/BEncryption.h         |  175 -
 external/badvpn_dns/security/BHash.c               |   69 -
 external/badvpn_dns/security/BHash.h               |   80 -
 external/badvpn_dns/security/BRandom.c             |   42 -
 external/badvpn_dns/security/BRandom.h             |   49 -
 external/badvpn_dns/security/BSecurity.c           |  149 -
 external/badvpn_dns/security/BSecurity.h           |   60 -
 external/badvpn_dns/security/CMakeLists.txt        |   10 -
 external/badvpn_dns/security/OTPCalculator.c       |  118 -
 external/badvpn_dns/security/OTPCalculator.h       |   96 -
 external/badvpn_dns/security/OTPChecker.c          |  297 --
 external/badvpn_dns/security/OTPChecker.h          |  148 -
 external/badvpn_dns/security/OTPGenerator.c        |  159 -
 external/badvpn_dns/security/OTPGenerator.h        |  134 -
 external/badvpn_dns/server/CMakeLists.txt          |   12 -
 external/badvpn_dns/server/badvpn-server.8         |  190 -
 external/badvpn_dns/server/server.c                | 2394 ----------
 external/badvpn_dns/server/server.h                |  186 -
 .../badvpn_dns/server_connection/CMakeLists.txt    |    5 -
 .../server_connection/SCKeepaliveSource.c          |   69 -
 .../server_connection/SCKeepaliveSource.h          |   72 -
 .../server_connection/ServerConnection.c           |  669 ---
 .../server_connection/ServerConnection.h           |  289 --
 external/badvpn_dns/socksclient/BSocksClient.c     |  608 ---
 external/badvpn_dns/socksclient/BSocksClient.h     |  147 -
 external/badvpn_dns/socksclient/CMakeLists.txt     |    1 -
 external/badvpn_dns/stringmap/BStringMap.c         |  198 -
 external/badvpn_dns/stringmap/BStringMap.h         |   57 -
 external/badvpn_dns/stringmap/CMakeLists.txt       |    1 -
 external/badvpn_dns/structure/BAVL.h               |  797 ----
 external/badvpn_dns/structure/CAvl.h               |   36 -
 external/badvpn_dns/structure/CAvl_decl.h          |   77 -
 external/badvpn_dns/structure/CAvl_footer.h        |  113 -
 external/badvpn_dns/structure/CAvl_header.h        |  141 -
 external/badvpn_dns/structure/CAvl_impl.h          |  949 ----
 external/badvpn_dns/structure/CHash.h              |   39 -
 external/badvpn_dns/structure/CHash_decl.h         |   59 -
 external/badvpn_dns/structure/CHash_footer.h       |   74 -
 external/badvpn_dns/structure/CHash_header.h       |   78 -
 external/badvpn_dns/structure/CHash_impl.h         |  312 --
 external/badvpn_dns/structure/ChunkBuffer2.h       |  317 --
 external/badvpn_dns/structure/IndexedList.h        |  225 -
 external/badvpn_dns/structure/IndexedList_tree.h   |   15 -
 external/badvpn_dns/structure/LinkedList0.h        |  202 -
 external/badvpn_dns/structure/LinkedList1.h        |  275 --
 external/badvpn_dns/structure/LinkedList3.h        |  362 --
 external/badvpn_dns/structure/SAvl.h               |   40 -
 external/badvpn_dns/structure/SAvl_decl.h          |   73 -
 external/badvpn_dns/structure/SAvl_footer.h        |   89 -
 external/badvpn_dns/structure/SAvl_header.h        |   93 -
 external/badvpn_dns/structure/SAvl_impl.h          |  164 -
 external/badvpn_dns/structure/SAvl_tree.h          |   18 -
 external/badvpn_dns/structure/SLinkedList.h        |   38 -
 external/badvpn_dns/structure/SLinkedList_decl.h   |   67 -
 external/badvpn_dns/structure/SLinkedList_footer.h |   57 -
 external/badvpn_dns/structure/SLinkedList_header.h |   62 -
 external/badvpn_dns/structure/SLinkedList_impl.h   |  182 -
 external/badvpn_dns/system/BAddr.h                 |  808 ----
 external/badvpn_dns/system/BConnection.h           |  369 --
 external/badvpn_dns/system/BConnectionGeneric.h    |  144 -
 external/badvpn_dns/system/BConnection_unix.c      | 1057 -----
 external/badvpn_dns/system/BConnection_unix.h      |   87 -
 external/badvpn_dns/system/BConnection_win.c       |  875 ----
 external/badvpn_dns/system/BConnection_win.h       |  101 -
 external/badvpn_dns/system/BDatagram.h             |  209 -
 external/badvpn_dns/system/BDatagram_unix.c        |  855 ----
 external/badvpn_dns/system/BDatagram_unix.h        |   71 -
 external/badvpn_dns/system/BDatagram_win.c         |  755 ---
 external/badvpn_dns/system/BDatagram_win.h         |   99 -
 external/badvpn_dns/system/BInputProcess.c         |  211 -
 external/badvpn_dns/system/BInputProcess.h         |   65 -
 external/badvpn_dns/system/BLockReactor.c          |  131 -
 external/badvpn_dns/system/BLockReactor.h          |   58 -
 external/badvpn_dns/system/BNetwork.c              |   99 -
 external/badvpn_dns/system/BNetwork.h              |   36 -
 external/badvpn_dns/system/BProcess.c              |  400 --
 external/badvpn_dns/system/BProcess.h              |  200 -
 external/badvpn_dns/system/BReactor.h              |   11 -
 external/badvpn_dns/system/BReactor_badvpn.c       | 1430 ------
 external/badvpn_dns/system/BReactor_badvpn.h       |  572 ---
 .../badvpn_dns/system/BReactor_badvpn_timerstree.h |   13 -
 external/badvpn_dns/system/BReactor_emscripten.c   |  176 -
 external/badvpn_dns/system/BReactor_emscripten.h   |   87 -
 external/badvpn_dns/system/BReactor_glib.c         |  524 ---
 external/badvpn_dns/system/BReactor_glib.h         |  148 -
 external/badvpn_dns/system/BSignal.c               |  188 -
 external/badvpn_dns/system/BSignal.h               |   64 -
 external/badvpn_dns/system/BThreadSignal.c         |  136 -
 external/badvpn_dns/system/BThreadSignal.h         |   53 -
 external/badvpn_dns/system/BTime.c                 |   38 -
 external/badvpn_dns/system/BTime.h                 |  163 -
 external/badvpn_dns/system/BUnixSignal.c           |  406 --
 external/badvpn_dns/system/BUnixSignal.h           |  132 -
 external/badvpn_dns/system/CMakeLists.txt          |   44 -
 external/badvpn_dns/tests/CMakeLists.txt           |    8 -
 external/badvpn_dns/tests/bproto_test.bproto       |    9 -
 external/badvpn_dns/tests/bproto_test.c            |   76 -
 external/badvpn_dns/tests/chunkbuffer2_test.c      |   86 -
 external/badvpn_dns/tests/threadwork_test.c        |   87 -
 external/badvpn_dns/threadwork/BThreadWork.c       |  451 --
 external/badvpn_dns/threadwork/BThreadWork.h       |  171 -
 external/badvpn_dns/threadwork/CMakeLists.txt      |    6 -
 external/badvpn_dns/tun2socks/CMakeLists.txt       |   15 -
 external/badvpn_dns/tun2socks/SocksUdpGwClient.c   |  228 -
 external/badvpn_dns/tun2socks/SocksUdpGwClient.h   |   64 -
 external/badvpn_dns/tun2socks/badvpn-tun2socks.8   |  126 -
 external/badvpn_dns/tun2socks/tun2socks.c          | 2138 ---------
 external/badvpn_dns/tun2socks/tun2socks.h          |   46 -
 external/badvpn_dns/tunctl/CMakeLists.txt          |    6 -
 external/badvpn_dns/tunctl/tunctl.c                |  352 --
 external/badvpn_dns/tuntap/BTap.c                  |  631 ---
 external/badvpn_dns/tuntap/BTap.h                  |  199 -
 external/badvpn_dns/tuntap/CMakeLists.txt          |   10 -
 external/badvpn_dns/tuntap/tapwin32-funcs.c        |  227 -
 external/badvpn_dns/tuntap/tapwin32-funcs.h        |   42 -
 external/badvpn_dns/tuntap/wintap-common.h         |   39 -
 external/badvpn_dns/udevmonitor/CMakeLists.txt     |    7 -
 external/badvpn_dns/udevmonitor/NCDUdevCache.c     |  417 --
 external/badvpn_dns/udevmonitor/NCDUdevCache.h     |   66 -
 external/badvpn_dns/udevmonitor/NCDUdevManager.c   |  547 ---
 external/badvpn_dns/udevmonitor/NCDUdevManager.h   |   84 -
 external/badvpn_dns/udevmonitor/NCDUdevMonitor.c   |  250 -
 external/badvpn_dns/udevmonitor/NCDUdevMonitor.h   |   71 -
 .../badvpn_dns/udevmonitor/NCDUdevMonitorParser.c  |  358 --
 .../badvpn_dns/udevmonitor/NCDUdevMonitorParser.h  |   76 -
 external/badvpn_dns/udpgw/CMakeLists.txt           |    9 -
 external/badvpn_dns/udpgw/udpgw.c                  | 1473 ------
 external/badvpn_dns/udpgw/udpgw.h                  |   52 -
 external/badvpn_dns/udpgw_client/CMakeLists.txt    |    1 -
 external/badvpn_dns/udpgw_client/UdpGwClient.c     |  597 ---
 external/badvpn_dns/udpgw_client/UdpGwClient.h     |  118 -
 971 files changed, 227043 deletions(-)

diff --git a/external/badvpn_dns/Android.mk b/external/badvpn_dns/Android.mk
deleted file mode 100644
index 3829065..0000000
--- a/external/badvpn_dns/Android.mk
+++ /dev/null
@@ -1,75 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := tun2socks
-
-LOCAL_CFLAGS := -std=gnu99
-LOCAL_CFLAGS += -DBADVPN_THREAD_SAFE=0 -DBADVPN_LINUX -DBADVPN_BREACTOR_BADVPN -D_GNU_SOURCE
-LOCAL_CFLAGS += -DBADVPN_USE_SELFPIPE -DBADVPN_USE_EPOLL
-LOCAL_CFLAGS += -DBADVPN_LITTLE_ENDIAN
-LOCAL_CFLAGS += -DPSIPHON
-
-LOCAL_C_INCLUDES:= \
-        $(LOCAL_PATH) \
-        $(LOCAL_PATH)/lwip/src/include/ipv4 \
-        $(LOCAL_PATH)/lwip/src/include/ipv6 \
-        $(LOCAL_PATH)/lwip/src/include \
-        $(LOCAL_PATH)/lwip/custom
-
-LOCAL_SRC_FILES := \
-        base/BLog_syslog.c \
-        system/BReactor_badvpn.c \
-        system/BSignal.c \
-        system/BConnection_unix.c \
-        system/BTime.c \
-        system/BUnixSignal.c \
-        system/BNetwork.c \
-        flow/StreamRecvInterface.c \
-        flow/PacketRecvInterface.c \
-        flow/PacketPassInterface.c \
-        flow/StreamPassInterface.c \
-        flow/SinglePacketBuffer.c \
-        flow/BufferWriter.c \
-        flow/PacketBuffer.c \
-        flow/PacketStreamSender.c \
-        flow/PacketPassConnector.c \
-        flow/PacketProtoFlow.c \
-        flow/PacketPassFairQueue.c \
-        flow/PacketProtoEncoder.c \
-        flow/PacketProtoDecoder.c \
-        socksclient/BSocksClient.c \
-        tuntap/BTap.c \
-        lwip/src/core/timers.c \
-        lwip/src/core/udp.c \
-        lwip/src/core/memp.c \
-        lwip/src/core/init.c \
-        lwip/src/core/pbuf.c \
-        lwip/src/core/tcp.c \
-        lwip/src/core/tcp_out.c \
-        lwip/src/core/netif.c \
-        lwip/src/core/def.c \
-        lwip/src/core/mem.c \
-        lwip/src/core/tcp_in.c \
-        lwip/src/core/stats.c \
-        lwip/src/core/inet_chksum.c \
-        lwip/src/core/ipv4/icmp.c \
-        lwip/src/core/ipv4/ip4.c \
-        lwip/src/core/ipv4/ip4_addr.c \
-        lwip/src/core/ipv4/ip_frag.c \
-        lwip/src/core/ipv6/ip6.c \
-        lwip/src/core/ipv6/nd6.c \
-        lwip/src/core/ipv6/icmp6.c \
-        lwip/src/core/ipv6/ip6_addr.c \
-        lwip/src/core/ipv6/ip6_frag.c \
-        lwip/custom/sys.c \
-        tun2socks/tun2socks.c \
-        base/DebugObject.c \
-        base/BLog.c \
-        base/BPending.c \
-        flowextra/PacketPassInactivityMonitor.c \
-        tun2socks/SocksUdpGwClient.c \
-        udpgw_client/UdpGwClient.c 
-
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/external/badvpn_dns/CMakeLists.txt b/external/badvpn_dns/CMakeLists.txt
deleted file mode 100644
index ebdc0d7..0000000
--- a/external/badvpn_dns/CMakeLists.txt
+++ /dev/null
@@ -1,408 +0,0 @@
-cmake_minimum_required(VERSION 2.8)
-project(BADVPN C)
-
-set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
-
-include(TestBigEndian)
-include(CheckIncludeFiles)
-include(CheckSymbolExists)
-include(CheckTypeSize)
-
-set(BUILD_COMPONENTS)
-
-macro (build_switch name text default)
-    if (BUILD_NOTHING_BY_DEFAULT)
-        option(BUILD_${name} "${text}" OFF)
-    else ()
-        option(BUILD_${name} "${text}" "${default}")
-    endif ()
-    list(APPEND BUILD_COMPONENTS "${name}")
-endmacro ()
-
-# detect Emscripten
-if (CMAKE_C_COMPILER MATCHES "/emcc$")
-    set(EMSCRIPTEN ON)
-else ()
-    set(EMSCRIPTEN OFF)
-endif ()
-
-if (EMSCRIPTEN)
-    set(ON_IF_NOT_EMSCRIPTEN OFF)
-else ()
-    set(ON_IF_NOT_EMSCRIPTEN ON)
-endif()
-
-if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT EMSCRIPTEN)
-    set(ON_IF_LINUX ON)
-else ()
-    set(ON_IF_LINUX OFF)
-endif()
-
-if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR EMSCRIPTEN)
-    set(ON_IF_LINUX_OR_EMSCRIPTEN ON)
-else ()
-    set(ON_IF_LINUX_OR_EMSCRIPTEN OFF)
-endif ()
-
-# define build defaults
-build_switch(EXAMPLES "build example programs" ON)
-build_switch(TESTS "build some other example programs" ON)
-build_switch(SERVER "build badvpn-server" ${ON_IF_NOT_EMSCRIPTEN})
-build_switch(CLIENT "build badvpn-client" ${ON_IF_NOT_EMSCRIPTEN})
-build_switch(FLOODER "build badvpn-flooder" ${ON_IF_NOT_EMSCRIPTEN})
-build_switch(TUN2SOCKS "build badvpn-tun2socks" ${ON_IF_NOT_EMSCRIPTEN})
-build_switch(UDPGW "build badvpn-udpgw" ${ON_IF_NOT_EMSCRIPTEN})
-build_switch(NCD "build badvpn-ncd" ${ON_IF_LINUX_OR_EMSCRIPTEN})
-build_switch(TUNCTL "build badvpn-tunctl" ${ON_IF_LINUX})
-build_switch(DOSTEST "build dostest-server and dostest-attacker" OFF)
-
-if (BUILD_NCD AND NOT (CMAKE_SYSTEM_NAME STREQUAL "Linux"))
-    message(FATAL_ERROR "NCD is only available on Linux")
-endif ()
-
-if (BUILD_CLIENT OR BUILD_SERVER)
-    find_package(OpenSSL REQUIRED)
-    set(LIBCRYPTO_INCLUDE_DIRS "${OpenSSL_INCLUDE_DIRS}")
-    set(LIBCRYPTO_LIBRARY_DIRS "${OpenSSL_LIBRARY_DIRS}")
-    set(LIBCRYPTO_LIBRARIES "${OpenSSL_LIBRARIES}")
-endif ()
-
-if (BUILD_SERVER OR BUILD_CLIENT OR BUILD_FLOODER)
-    find_package(NSPR REQUIRED)
-    find_package(NSS REQUIRED)
-endif ()
-
-# choose reactor
-if (DEFINED BREACTOR_BACKEND)
-    if (NOT (BREACTOR_BACKEND STREQUAL "badvpn" OR BREACTOR_BACKEND STREQUAL "glib"))
-        message(FATAL_ERROR "unknown reactor backend specified")
-    endif ()
-else ()
-    if (EMSCRIPTEN)
-        set(BREACTOR_BACKEND "emscripten")
-    else ()
-        set(BREACTOR_BACKEND "badvpn")
-    endif ()
-endif ()
-
-if (BREACTOR_BACKEND STREQUAL "badvpn")
-    add_definitions(-DBADVPN_BREACTOR_BADVPN)
-elseif (BREACTOR_BACKEND STREQUAL "glib")
-    if (NOT (CMAKE_SYSTEM_NAME STREQUAL "Linux"))
-        message(FATAL_ERROR "GLib reactor backend is only available on Linux")
-    endif ()
-    find_package(GLIB2 REQUIRED)
-    add_definitions(-DBADVPN_BREACTOR_GLIB)
-elseif (BREACTOR_BACKEND STREQUAL "emscripten")
-    add_definitions(-DBADVPN_BREACTOR_EMSCRIPTEN)
-endif ()
-
-include_directories(
-    ${CMAKE_CURRENT_SOURCE_DIR}
-    ${LIBCRYPTO_INCLUDE_DIRS}
-    ${NSPR_INCLUDE_DIRS}
-    ${NSS_INCLUDE_DIRS}
-    ${GLIB2_INCLUDE_DIR}
-    lwip/custom
-    lwip/src/include
-    lwip/src/include/ipv4
-    lwip/src/include/ipv6
-)
-
-link_directories(
-    ${LIBCRYPTO_LIBRARY_DIRS}
-    ${NSPR_LIBRARY_DIRS}
-    ${NSS_LIBRARY_DIRS}
-)
-
-test_big_endian(BIG_ENDIAN)
-
-check_type_size(int INT_SIZE)
-if (NOT (INT_SIZE GREATER "3"))
-    message(FATAL_ERROR "int must be at least 32 bits")
-endif ()
-
-check_type_size(size_t SIZE_SIZE)
-if (NOT (SIZE_SIZE GREATER INT_SIZE OR SIZE_SIZE EQUAL INT_SIZE))
-    message(FATAL_ERROR "size_t must be greater or equal than int")
-endif ()
-
-if (MSVC)
-    add_definitions(/TP -D_CRT_SECURE_NO_WARNINGS /wd4065 /wd4018 /wd4533 /wd4244 /wd4102)
-else ()
-    add_definitions(-std=gnu99 -Wall -Wno-unused-value -Wno-parentheses -Wno-switch -Wredundant-decls)
-
-    if (NOT CMAKE_C_COMPILER_ID STREQUAL "PathScale")
-        add_definitions(-Werror=implicit-function-declaration -Wno-switch-enum -Wno-unused-function
-                        -Wstrict-aliasing)
-    endif ()
-    
-    if (CMAKE_C_COMPILER_ID MATCHES "^Clang")
-        add_definitions(-Wno-initializer-overrides -Wno-tautological-constant-out-of-range-compare)
-    endif ()
-endif ()
-
-# platform-specific stuff
-if (WIN32)
-    add_definitions(-DBADVPN_USE_WINAPI -D_WIN32_WINNT=0x600 -DWIN32_LEAN_AND_MEAN)
-    add_definitions(-DBADVPN_THREAD_SAFE=0)
-
-    set(CMAKE_REQUIRED_DEFINITIONS "-D_WIN32_WINNT=0x600")
-    check_symbol_exists(WSAID_WSASENDMSG "winsock2.h;mswsock.h" HAVE_MSW_1)
-    check_symbol_exists(WSAID_WSARECVMSG "winsock2.h;mswsock.h" HAVE_MSW_2)
-    check_symbol_exists(WSAID_ACCEPTEX "winsock2.h;mswsock.h" HAVE_MSW_3)
-    check_symbol_exists(WSAID_GETACCEPTEXSOCKADDRS "winsock2.h;mswsock.h" HAVE_MSW_4)
-    check_symbol_exists(WSAID_CONNECTEX "winsock2.h;mswsock.h" HAVE_MSW_5)
-    set(CMAKE_REQUIRED_DEFINITIONS "")
-    if (NOT (HAVE_MSW_1 AND HAVE_MSW_2 AND HAVE_MSW_3 AND HAVE_MSW_4 AND HAVE_MSW_5))
-        add_definitions(-DBADVPN_USE_SHIPPED_MSWSOCK)
-        check_type_size(WSAMSG HAVE_WSAMSG)
-        if (NOT HAVE_WSAMSG)
-            add_definitions(-DBADVPN_SHIPPED_MSWSOCK_DECLARE_WSAMSG)
-        endif ()
-    endif ()
-else ()
-    set(BADVPN_THREADWORK_USE_PTHREAD 1)
-    add_definitions(-DBADVPN_THREADWORK_USE_PTHREAD)
-    add_definitions(-DBADVPN_THREAD_SAFE=1)
-
-    link_libraries(rt)
-
-    if (EMSCRIPTEN)
-        add_definitions(-DBADVPN_EMSCRIPTEN)
-        add_definitions(-DBADVPN_NO_PROCESS -DBADVPN_NO_UDEV -DBADVPN_NO_RANDOM)
-    elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
-        add_definitions(-DBADVPN_LINUX)
-
-        check_include_files(sys/signalfd.h HAVE_SYS_SIGNALFD_H)
-        if (HAVE_SYS_SIGNALFD_H)
-            add_definitions(-DBADVPN_USE_SIGNALFD)
-        else ()
-            add_definitions(-DBADVPN_USE_SELFPIPE)
-        endif ()
-
-        check_include_files(sys/epoll.h HAVE_SYS_EPOLL_H)
-        if (HAVE_SYS_EPOLL_H)
-            add_definitions(-DBADVPN_USE_EPOLL)
-        else ()
-            add_definitions(-DBADVPN_USE_POLL)
-        endif ()
-
-        check_include_files(linux/rfkill.h HAVE_LINUX_RFKILL_H)
-        if (HAVE_LINUX_RFKILL_H)
-            add_definitions(-DBADVPN_USE_LINUX_RFKILL)
-            set(BADVPN_USE_LINUX_RFKILL 1)
-        endif ()
-
-        check_include_files(linux/input.h HAVE_LINUX_INPUT_H)
-        if (HAVE_LINUX_INPUT_H)
-            add_definitions(-DBADVPN_USE_LINUX_INPUT)
-            set(BADVPN_USE_LINUX_INPUT 1)
-        endif ()
-
-        check_include_files(sys/inotify.h HAVE_SYS_INOTIFY_H)
-        if (HAVE_SYS_INOTIFY_H)
-            add_definitions(-DBADVPN_USE_INOTIFY)
-            set(BADVPN_USE_INOTIFY 1)
-        endif ()
-    elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
-        add_definitions(-DBADVPN_FREEBSD)
-
-        check_symbol_exists(kqueue "sys/types.h;sys/event.h;sys/time.h" HAVE_KQUEUE)
-        if (NOT HAVE_KQUEUE)
-            message(FATAL_ERROR "kqueue is required")
-        endif ()
-        add_definitions(-DBADVPN_USE_KEVENT)
-    endif ()
-
-    if (NOT DEFINED BADVPN_WITHOUT_CRYPTODEV)
-        check_include_files(crypto/cryptodev.h HAVE_CRYPTO_CRYPTODEV_H)
-        if (HAVE_CRYPTO_CRYPTODEV_H)
-            add_definitions(-DBADVPN_USE_CRYPTODEV)
-        elseif (DEFINED BADVPN_WITH_CRYPTODEV)
-            message(FATAL_ERROR "crypto/cryptodev.h not found")
-        endif ()
-    endif ()
-endif ()
-
-# check for syslog
-check_include_files(syslog.h HAVE_SYSLOG_H)
-if (HAVE_SYSLOG_H)
-    add_definitions(-DBADVPN_USE_SYSLOG)
-endif ()
-
-# add preprocessor definitions
-if (BIG_ENDIAN)
-    add_definitions(-DBADVPN_BIG_ENDIAN)
-else ()
-    add_definitions(-DBADVPN_LITTLE_ENDIAN)
-endif ()
-
-# install man pages
-install(
-    FILES badvpn.7
-    DESTINATION share/man/man7
-)
-
-# reset variables indicating whether we're building various libraries,
-# and set them in the respective CMakeLists files. This is used to disable
-# building examples and tests which require libraries that are not available.
-set(BUILDING_SECURITY 0)
-set(BUILDING_DHCPCLIENT 0)
-set(BUILDING_ARPPROBE 0)
-set(BUILDING_BKIO 0)
-set(BUILDING_PREDICATE 0)
-set(BUILDING_UDEVMONITOR 0)
-set(BUILDING_THREADWORK 0)
-set(BUILDING_RANDOM 0)
-
-# Used to register an internal library.
-# This will also add a library with the -plugin suffix, which is useful
-# for use by dynamic libraries (e.g. NCD modules):
-# - If BUILD_SHARED_LIBS is off (default), the libraries ${LIB_NAME} and ${LIB_NAME}-plugin
-#   are built separately. Both are static libraries but the -plugin variant is build as position
-#   independent code, so it can be (statically) linked into dynamic libraries.
-# - If BUILD_SHARED_LIBS is on, only ${LIB_NAME} is built, as a shared library.
-#   The ${LIB_NAME}-plugin target is set up as an alias to ${LIB_NAME}.
-function(badvpn_add_library LIB_NAME LINK_BADVPN_LIBS LINK_SYS_LIBS LIB_SOURCES)
-    set(BADVPN_LIBS_EXEC)
-    set(BADVPN_LIBS_PLUGIN)
-    foreach(LIB ${LINK_BADVPN_LIBS})
-        list(APPEND BADVPN_LIBS_EXEC "${LIB}")
-        list(APPEND BADVPN_LIBS_PLUGIN "${LIB}-plugin")
-    endforeach()
-
-    add_library("${LIB_NAME}" ${LIB_SOURCES})
-    target_link_libraries("${LIB_NAME}" ${BADVPN_LIBS_EXEC} ${LINK_SYS_LIBS})
-    set_target_properties("${LIB_NAME}" PROPERTIES OUTPUT_NAME "badvpn-${LIB_NAME}")
-
-    if (BUILD_SHARED_LIBS)
-        add_library("${LIB_NAME}-plugin" ALIAS "${LIB_NAME}")
-    else ()
-        add_library("${LIB_NAME}-plugin" STATIC ${LIB_SOURCES})
-        target_link_libraries("${LIB_NAME}-plugin" ${BADVPN_LIBS_PLUGIN} ${LINK_SYS_LIBS})
-        set_target_properties("${LIB_NAME}-plugin" PROPERTIES OUTPUT_NAME "badvpn-${LIB_NAME}-plugin")
-        set_target_properties("${LIB_NAME}-plugin" PROPERTIES POSITION_INDEPENDENT_CODE YES)
-        set_target_properties("${LIB_NAME}-plugin" PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -DBADVPN_PLUGIN")
-    endif()
-endfunction()
-
-# internal libraries
-add_subdirectory(base)
-add_subdirectory(system)
-add_subdirectory(flow)
-add_subdirectory(flowextra)
-if (OpenSSL_FOUND)
-    set(BUILDING_SECURITY 1)
-    add_subdirectory(security)
-endif ()
-if (NSS_FOUND)
-    add_subdirectory(nspr_support)
-endif ()
-if (BUILD_CLIENT OR BUILDING_SECURITY)
-    set(BUILDING_THREADWORK 1)
-    add_subdirectory(threadwork)
-endif ()
-if (BUILD_CLIENT OR BUILD_TUN2SOCKS)
-    add_subdirectory(tuntap)
-endif ()
-if (BUILD_SERVER)
-    set(BUILDING_PREDICATE 1)
-    add_subdirectory(predicate)
-endif ()
-if (BUILD_CLIENT OR BUILD_FLOODER)
-    add_subdirectory(server_connection)
-endif ()
-if (BUILD_NCD AND NOT EMSCRIPTEN)
-    set(BUILDING_DHCPCLIENT 1)
-    set(BUILDING_ARPPROBE 1)
-    set(BUILDING_UDEVMONITOR 1)
-    set(BUILDING_RANDOM 1)
-    add_subdirectory(stringmap)
-    add_subdirectory(udevmonitor)
-    add_subdirectory(dhcpclient)
-    add_subdirectory(arpprobe)
-    add_subdirectory(random)
-endif ()
-if (BUILD_TUN2SOCKS)
-    add_subdirectory(socksclient)
-    add_subdirectory(udpgw_client)
-    add_subdirectory(lwip)
-endif ()
-if (BUILD_TUNCTL)
-    add_subdirectory(tunctl)
-endif ()
-
-# example programs
-if (BUILD_EXAMPLES)
-    add_subdirectory(examples)
-endif ()
-
-# tests
-if (BUILD_TESTS)
-    add_subdirectory(tests)
-endif ()
-
-# server
-if (BUILD_SERVER)
-    add_subdirectory(server)
-endif ()
-
-# client
-if (BUILD_CLIENT)
-    add_subdirectory(client)
-endif ()
-
-# flooder
-if (BUILD_FLOODER)
-    add_subdirectory(flooder)
-endif ()
-
-# tun2socks
-if (BUILD_TUN2SOCKS)
-    add_subdirectory(tun2socks)
-endif ()
-
-# udpgw
-if (BUILD_UDPGW)
-    add_subdirectory(udpgw)
-endif ()
-
-# ncd
-if (BUILD_NCD)
-    add_subdirectory(ncd)
-    if (NOT EMSCRIPTEN)
-        add_subdirectory(ncd-request)
-    endif ()
-endif ()
-
-# dostest
-if (BUILD_DOSTEST)
-    add_subdirectory(dostest)
-endif ()
-
-message(STATUS "Building components:")
-
-# print what we're building and what not
-foreach (name ${BUILD_COMPONENTS})
-    # to lower name
-    string(TOLOWER "${name}" name_withspaces)
-
-    # append spaces to name
-    #while (TRUE)
-    #    string(LENGTH "${name_withspaces}" length)
-    #    if (NOT (length LESS 12))
-    #        break()
-    #    endif ()
-    #    set(name_withspaces "${name_withspaces} ")
-    #endwhile ()
-    
-    # determine if we're building
-    if (BUILD_${name})
-        set(building "yes")
-    else ()
-        set(building "no")
-    endif ()
-    
-    message(STATUS "    ${name_withspaces} ${building}")
-endforeach ()
diff --git a/external/badvpn_dns/COPYING b/external/badvpn_dns/COPYING
deleted file mode 100644
index f973347..0000000
--- a/external/badvpn_dns/COPYING
+++ /dev/null
@@ -1,24 +0,0 @@
-Copyright (c) 2009, Ambroz Bizjak <ambrop7 at gmail.com>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright
-      notice, this list of conditions and the following disclaimer in the
-      documentation and/or other materials provided with the distribution.
-    * Neither the name of the author nor the
-      names of its contributors may be used to endorse or promote products
-      derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/external/badvpn_dns/ChangeLog b/external/badvpn_dns/ChangeLog
deleted file mode 100644
index 4c4b96b..0000000
--- a/external/badvpn_dns/ChangeLog
+++ /dev/null
@@ -1,216 +0,0 @@
-Version 1.999.129:
-
-- ncd: modules: file_open: Fix typo in assertion.
-
-- server: Fix bug forgetting to call BSSLConnection_ReleaseBuffers(). Unless threads are enabled, this is an assert failure if NDEBUG is not defined an a non-issue otherwise.
-
-- ncd: Look for various programs in PATH instead of hardcoded paths.
-
-- Add compile-udpgw.sh.
-
-- ncd: modules: net_dns: Implement net.dns.resolvconf() forspecification of arbitrary resolv.conf lines
-
-Version 1.999.128:
-
-- tun2socks: add option --append-source-to-username to give the SOCKS server the source IP of the connection
-
-- tun2socks: IPv6 support, and updated to newer version of lwIP
-
-- tun2socks: fix some bugs/crashes
-
-- tun2socks, udpgw: transparent DNS forwarding, though no Windows support on udpgw side (contributed by Kerem Hadimli)
-
-- NCD: preliminary support for dynamically loading commands
-
-Version 1.999.127:
-
-- client, server: implement experimental support for performing SSL operations in worker threads. Currently it's rather inefficient.
-
-- NCD: modules: value: implement value::append() for appending to a list
-
-- NCD: modules: net_iptables: add single-argument form of append and insert commands, allowing for generic use
-
-- NCD: modules: net_iptables: implement net.iptables.insert() and net.ebtables.insert()
-
-- NCD: modules: sys_start_process: implement options, including username, term_on_deinit and deinit_kill_time
-
-- NCD: modules: sys_request_server: implement _caller in request handler
-
-- NCD: modules: add getenv()
-
-- NCD: modules: daemon: implement options, including username option
-
-- NCD: modules: runonce: add new options format with a map, implement username option
-
-- NCD: modules: add buffer(), which exposes a buffer with efficient appending and removing from the beginning.
-
-- NCD: add a new internal string representation called ComposedString. This allows modules to expose the concatenation of multiple memroy buffers as a single string value, efficiently.
-
-- fix many, hopefully all, strict aliasing violations. In particular, this fixes a bug where the DHCP client integrated into NCD won't work correctly, subject to optimization flags.
-
-- NCD: modules: sleep: interpret empty string as no sleeping, add sleep(ms_start) with one argument
-
-- NCD: modules: add log(), log_r() and log_fr() commands for logging via the BLog system
-
-Version 1.999.126:
-
-- NCD: modules: sleep: interpret empty string time as no sleeping, add sleep(ms_start) with one argument
-
-- NCD: modules: add log module for message logging using the BLog system
-
-- NCD: implement the "include" and "include_guard" directives, which allow separating reusable code into files
-
-- NCD: modules: call2: implement call_with_caller_target(), which makes it easier to write reusable code that calls back user-provided code
-
-- NCD: modules: call2: remove call2_if(), call2_ifelse(), embcall2(), embcall2_if(), embcall2_ifelse()
-
-- NCD: modules: add sys.start_process(), which implements starting and controlling external processes and reading/writing their stdout/stdin
-
-- tun2socks: implement SOCKS password authentication
-
-- NCD: track the depth of values and limit the maximum depth. This avoids stack overflow with very deeply nested values.
-
-- NCD: modules: add substr()
-
-- NCD: process_manager: add 2-argument start() method which doesn't take a process identifier
-
-- NCD: process_manager: allow process identifiers to be any value not just strings
-
-- NCD: multidepend, depend_scope: fix immediate effect order when a depend finishes backtracking
-
-- NCD: add depend_scope module to do exactly what the multidepend module does, but with separate non-global dependency name scopes
-
-- NCD: multidepend: allow dependency names to be any value not just strings
-
-- NCD: implement value::insert(what) for appending to a list
-
-- NCD: change the format of addresses in sys.request_server() and sys.request_client() to be the same as in the socket module
-
-- NCD: add socket module (sys.connect() and sys.listen())
-
-- NCD: fix bug where duplicate template/process names would not be detected and weird behaviour would result
-
-- NCD: add backtrack_point() for simple backtracking
-
-- NCD: add file_open() for more complete file I/O
-
-- NCD: implement parse_ipv6_addr() and parse_ipv6_cidr_addr()
-
-- NCD: port to Emscripten/Javascript, for the in-browser demo
-
-- NCD: many performance and memory usage improvements
-
-- NCD: add assert_false()
-
-- NCD: don't link to OpenSSL to for random number generator. Use /dev/urandom instead to generate XIDs for DHCP.
-
-- NCD: deprecate ip_in_network() and instead add net.ipv{4,6}.addr_in_network(), net.ipv{4,6}.ifnot_addr_in_network()
-
-- NCD: implement some IPv6 modules: net.ipv6.addr(), net.ipv6.route()
-
-- NCD: support CIDR style addr/prefix addresses in various modules
-
-- NCD: recognize Elif and Else with capital first letter to be consistent with other reserved keywords
-
-Version 1.999.123:
-
-- NCD: performance improvements related to finding modules for statements
-
-- NCD: performance improvements related to resolving object names
-
-- NCD: performance improvements related to instantiating statement arguments
-
-- NCD: add value::replace_this() and value::replace_this_undo()
-
-- NCD: add value::reset()
-
-- NCD: add value::replace() and value::replace_undo()
-
-- Port to compile with MSVC for Windows.
-
-- NCD: add Foreach clause
-
-- NCD: implement _caller in spawn(), add spawn::join()
-
-- NCD: add explode()
-
-- NCD: add hard_reboot() and hard_poweroff()
-
-- NCD: add file_stat() and file_lstat()
-
-- NCD: fix regex_replace() semantics. It was very broken because it did a complete replacement pass for every regex on the list, so it would match parts that have already been replaced, producing unexpected results.
-
-- NCD: small performance improvement
-
-Version 1.999.121:
-
-- NCD: improve error handling semantics; see http://code.google.com/p/badvpn/source/detail?r=1376
-
-- NCD: fix assertion failure in sys.evdev() if a device error occurs (e.g. device unplugged) while an event is being processed. Similar fix in some other modules, but these may not be reproducable.
-
-- NCD: some more performance improvements
-
-- NCD: some performance improvements (~30% faster interpretation of cpu-bound code)
-
-- NCD: implemented If..elif..else clause.
-
-- NCD: net.backend.wpa_supplicant: fix to work with wpa_supplicant>=1.0
-
-Version 1.999.115:
-
-- NCD: Many improvements; new statements, including call(), alias(), foreach(), choose().
-
-Version 1.999.113:
-
-- NCD: when starting child processes, make sure that file descriptors for standard
-  streams are always open in the child, by opening /dev/null if they are not.
-
-- Improve build system to allow selective building of components.
-  By default, everything is built, unless -DBUILD_NOTHING_BY_DEFAULT=1 is given.
-  Individual components can then be enabled or disabled using -DBUILD_COMPONENT=1
-  and -DBUILD_COMPONENT=0.
-
-- When starting any BadVPN program, make sure that file descriptors for standard
-  streams are always open in the child, by opening /dev/null if they are not.
-
-- NCD: net.backend.wpa_supplicant(): add 'bssid' and 'ssid' variables to allow
-  determining what wireless network wpa_supplicant connected to.
-
-- NCD: net.backend.wpa_supplicant(): do not require the user to start wpa_supplicant via
-  stdbuf, but do it automatically.
-
-Version 1.999.111:
-
-- Improved protocol such that peers can use SSL when comminicating via the server. This
-  improves security, as compromising the server will not allow the attacker to see secret
-  data shared by peers (in particular, encryption keys and OTP seeds when in UDP mode).
-
-  Compatibility is preserved if an only if the following conditions are met:
-  - The server is using the latest version.
-  - If the network is using SSL, all clients using the new version are using the
-    "--allow-peer-talk-without-ssl" command line option.
-
-  Be aware, however, that using the "--allow-peer-talk-without-ssl" option negates the
-  security benefits of the new SSL support - not only between pairs of peers where one
-  peer is using the old version, but also between pairs where both peers are capable
-  of SSL. This is because the server can re-initialize the pair, telling them not to use
-  SSL.
-
-Version 1.999.107:
-
-- Added Windows IOCP support, removing the limitation on ~64 connections. This is important
-  for tun2socks, which may have to handle several hundred connections.
-
-Version 1.999.105.2:
-
-- Fixed an assertion failure in tun2socks related to sending data to SOCKS.
-
-Version 1.999.101.3:
-
-- Fixed UDP transport on Windows 7 which didn't work (was only tested on XP).
-
-Version 1.999.101:
-
-- Fixed a protocol issue present in versions <=1.999.100.3. Compatibility is preserved in
-  case of a new server and old clients, but it is not possible to connect to an old server
-  with a new client.
diff --git a/external/badvpn_dns/INSTALL b/external/badvpn_dns/INSTALL
deleted file mode 100644
index 3605f4e..0000000
--- a/external/badvpn_dns/INSTALL
+++ /dev/null
@@ -1,76 +0,0 @@
-1 Requirements
-
-1.1 Operating system
-
-Linux:
-- Linux kernel 2.6. Kernel 2.4 will work, but performance will suffer.
-- tested on x86, x86_64 and ARM architectures. Not tested on any big-endian architecture.
-
-Windows:
-- Windows XP or newer; tested on Windows XP and Windows 7
-
-FreeBSD:
-- Not regularly tested.
-
-Other systems are not supported.
-
-1.2 Compilers
-
-Linux:
-  - gcc
-  - clang, except >=3.0 (clang bug http://llvm.org/bugs/show_bug.cgi?id=11535)
-
-Windows:
-  - gcc from the mingw-w64 project for 32-bit targets
-
-C language features used:
-  - Standard (all part of C99):
-    - designated initializers
-    - stdint.h, inttypes.h, stddef.h
-    - intermingled declarations and code
-    - for loop initial declaration
-    - one-line "//" comments
-  - Extensions:
-    - packed structure attribute (to pack a structure and allow unaligned access)
-
-1.3 CMake
-
-The build system uses CMake.
-
-1.4 OpenSSL
-
-Libcrypto (part of OpenSSL) is used for block ciphers, hash functions and random data generation.
-
-1.5 Network Security Services (NSS)
-
-The NSS library from Mozilla is used for TLS support. NSS command-line tools are also needed
-for setting up certificates.
-
-1.6 TAP-Win32 (Windows only) (runtime only)
-
-The TAP-Win32 driver, part of OpenVPN.
-
-2 Compilation
-
-2.1 Compiling on Linux
-
-$ tar xf badvpn-<version>.tar.bz2
-$ mkdir build
-$ cd build
-$ cmake ../badvpn-<version> -DCMAKE_INSTALL_PREFIX=/usr/local
-$ make
-If you want to install it, run as root:
-# make install
-
-If you only want NCD or tun2socks and not the VPN system, you can avoid the NSS dependency by passing
-the following to the cmake command:
--DBUILD_NCD=1 -DBUILD_TUN2SOCKS=1 -DBUILD_NOTHING_BY_DEFAULT=1
-
-2.2 Compiling for Windows
-
-See the file INSTALL-WINDOWS for detailed instructions.
-
-3 Usage
-
-The primary documentation is on the BadVPN homepage, http://code.google.com/p/badvpn/ .
-Additionally, some man pages are installed (badvpn(7), badvpn-server(8), badvpn-client(8)).
diff --git a/external/badvpn_dns/INSTALL-WINDOWS b/external/badvpn_dns/INSTALL-WINDOWS
deleted file mode 100644
index 9f0d5cf..0000000
--- a/external/badvpn_dns/INSTALL-WINDOWS
+++ /dev/null
@@ -1,72 +0,0 @@
-There are many ways to build BadVPN for Windows. It can be built with MSVC or GCC compilers,
-and it be built natively from Windows or cross-compiled from Linux. However, this document
-only describes building natively from Windows using MSVC.
-
-1. Get a MSVC compiler, e.g. from Visual Studio, Visual Studio Express or from the Windows SDK.
-
-2. Choose a directory where built stuff will be installed into; we call it <root>.
-
-3. Build the NSS library.
-   NOTE: you can also use the prebuilt version in the BadVPN windows download.
-
-    - Install MozillaBuild:
-        http://ftp.mozilla.org/pub/mozilla.org/mozilla/libraries/win32/MozillaBuildSetup-Latest.exe .
-
-    - Download the NSS source code that includes NSPR. As of the time of writing the latest version was 3.13.5:
-      https://ftp.mozilla.org/pub/mozilla.org/security/nss/releases/NSS_3_13_5_RTM/src/nss-3.13.5-with-nspr-4.9.1.tar.gz .
-
-      Extract it to c:\ so that you have C:\mozilla .
-
-    - Open a terminal with access to the Visual Studio compilers and other tools. E.g. if you use the Windows SDK,
-      activate the following start menu item: Programs -> Microsoft Windows SDK v7.1 -> Windows SDK 7.1 Command Prompt.
-
-    - In this terminal, run:
-
-      > c:\mozilla-build\start-l10n.bat
-
-    - Either a new terminal opens with a bash shell, or a bash shell starts in the existing terminal. Either way,
-      enter the following commands to finally build NSS: (here paths are written as /driveletter/...)
-
-      $ export OS_TARGET=WINNT
-      $ export BUILD_OPT=1
-      $ cd <nss_source_dir>/mozilla/security/nss
-      $ make nss_build_all
-
-      Now use a script shipped with the BadVPN source to copy the resulting files into appropriate directories within <root>:
-
-      $ <badvpn_source_dir>/scripts/copy_nss ../../dist <root>
-
-4. Build the OpenSSL library.
-   NOTE: you can also use the prebuilt version in the BadVPN windows download.
-
-    - Install ActivePerl.
-
-    - Download the OpenSSL source code and extract it.
-
-    - Open a compiler terminal, as was done when building NSS. Inside it, run:
-
-      > cd <openssl_source_dir>
-      > perl Configure VC-WIN32 --prefix=<root>
-      > ms\do_ms
-      > nmake -f ms\ntdll.mak
-
-      To copy the results into <root>:
-
-      > nmake -f ms\ntdll.mak install
-
-5. Build BadVPN.
-
-    - Install CMake. During installation, select the option to include cmake in PATH
-      to avoid having to type a long path into the terminal.
-
-    - Create an empty folder where BadVPN will be built; call it <build>.
-
-    - Open a compiler terminal. Inside it, run:
-
-      > cd <build>
-      > cmake <badvpn_source_dir> -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX=<root> -DCMAKE_BUILD_TYPE=Release
-      > nmake
-
-      To copy the results into <root>:
-
-      > nmake install
diff --git a/external/badvpn_dns/arpprobe/BArpProbe.c b/external/badvpn_dns/arpprobe/BArpProbe.c
deleted file mode 100644
index 2e6feb4..0000000
--- a/external/badvpn_dns/arpprobe/BArpProbe.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/**
- * @file BArpProbe.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <sys/ioctl.h>
-#include <linux/filter.h>
-
-#include <misc/debug.h>
-#include <misc/byteorder.h>
-#include <misc/ethernet_proto.h>
-#include <misc/ipv4_proto.h>
-#include <misc/udp_proto.h>
-#include <misc/get_iface_info.h>
-#include <base/BLog.h>
-
-#include "BArpProbe.h"
-
-#include <generated/blog_channel_BArpProbe.h>
-
-#define STATE_INITIAL 1
-#define STATE_NOEXIST 2
-#define STATE_EXIST 3
-#define STATE_EXIST_PANIC 4
-
-static void dgram_handler (BArpProbe *o, int event)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    BLog(BLOG_ERROR, "packet socket error");
-    
-    // report error
-    DEBUGERROR(&o->d_err, o->handler(o->user, BARPPROBE_EVENT_ERROR));
-    return;
-}
-
-static void send_request (BArpProbe *o)
-{
-    if (o->send_sending) {
-        BLog(BLOG_ERROR, "cannot send packet while another packet is being sent!");
-        return;
-    }
-    
-    // build packet
-    struct arp_packet *arp = &o->send_packet;
-    arp->hardware_type = hton16(ARP_HARDWARE_TYPE_ETHERNET);
-    arp->protocol_type = hton16(ETHERTYPE_IPV4);
-    arp->hardware_size = hton8(6);
-    arp->protocol_size = hton8(4);
-    arp->opcode = hton16(ARP_OPCODE_REQUEST);
-    memcpy(arp->sender_mac, o->if_mac, 6);
-    arp->sender_ip = hton32(0);
-    memset(arp->target_mac, 0, sizeof(arp->target_mac));
-    arp->target_ip = o->addr;
-    
-    // send packet
-    PacketPassInterface_Sender_Send(o->send_if, (uint8_t *)&o->send_packet, sizeof(o->send_packet));
-    
-    // set sending
-    o->send_sending = 1;
-}
-
-static void send_if_handler_done (BArpProbe *o)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->send_sending)
-    
-    // set not sending
-    o->send_sending = 0;
-}
-
-static void recv_if_handler_done (BArpProbe *o, int data_len)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(data_len >= 0)
-    ASSERT(data_len <= sizeof(struct arp_packet))
-    
-    // receive next packet
-    PacketRecvInterface_Receiver_Recv(o->recv_if, (uint8_t *)&o->recv_packet);
-    
-    if (data_len != sizeof(struct arp_packet)) {
-        BLog(BLOG_WARNING, "receive: wrong size");
-        return;
-    }
-    
-    struct arp_packet *arp = &o->recv_packet;
-    
-    if (ntoh16(arp->hardware_type) != ARP_HARDWARE_TYPE_ETHERNET) {
-        BLog(BLOG_WARNING, "receive: wrong hardware type");
-        return;
-    }
-    
-    if (ntoh16(arp->protocol_type) != ETHERTYPE_IPV4) {
-        BLog(BLOG_WARNING, "receive: wrong protocol type");
-        return;
-    }
-    
-    if (ntoh8(arp->hardware_size) != 6) {
-        BLog(BLOG_WARNING, "receive: wrong hardware size");
-        return;
-    }
-    
-    if (ntoh8(arp->protocol_size) != 4) {
-        BLog(BLOG_WARNING, "receive: wrong protocol size");
-        return;
-    }
-    
-    if (ntoh16(arp->opcode) != ARP_OPCODE_REPLY) {
-        return;
-    }
-    
-    if (arp->sender_ip != o->addr) {
-        return;
-    }
-    
-    int old_state = o->state;
-    
-    // set minus one missed
-    o->num_missed = -1;
-    
-    // set timer
-    BReactor_SetTimerAfter(o->reactor, &o->timer, BARPPROBE_EXIST_WAITSEND);
-    
-    // set state exist
-    o->state = STATE_EXIST;
-    
-    // report exist if needed
-    if (old_state == STATE_INITIAL || old_state == STATE_NOEXIST) {
-        o->handler(o->user, BARPPROBE_EVENT_EXIST);
-        return;
-    }
-}
-
-static void timer_handler (BArpProbe *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    // send request
-    send_request(o);
-    
-    switch (o->state) {
-        case STATE_INITIAL: {
-            ASSERT(o->num_missed >= 0)
-            ASSERT(o->num_missed < BARPPROBE_INITIAL_NUM_ATTEMPTS)
-            
-            // increment missed
-            o->num_missed++;
-            
-            // all attempts failed?
-            if (o->num_missed == BARPPROBE_INITIAL_NUM_ATTEMPTS) {
-                // set timer
-                BReactor_SetTimerAfter(o->reactor, &o->timer, BARPPROBE_NOEXIST_WAITRECV);
-                
-                // set state noexist
-                o->state = STATE_NOEXIST;
-                
-                // report noexist
-                o->handler(o->user, BARPPROBE_EVENT_NOEXIST);
-                return;
-            }
-            
-            // set timer
-            BReactor_SetTimerAfter(o->reactor, &o->timer, BARPPROBE_INITIAL_WAITRECV);
-        } break;
-        
-        case STATE_NOEXIST: {
-            // set timer
-            BReactor_SetTimerAfter(o->reactor, &o->timer, BARPPROBE_NOEXIST_WAITRECV);
-        } break;
-        
-        case STATE_EXIST: {
-            ASSERT(o->num_missed >= -1)
-            ASSERT(o->num_missed < BARPPROBE_EXIST_NUM_NOREPLY)
-            
-            // increment missed
-            o->num_missed++;
-            
-            // all missed?
-            if (o->num_missed == BARPPROBE_EXIST_NUM_NOREPLY) {
-                // set timer
-                BReactor_SetTimerAfter(o->reactor, &o->timer, BARPPROBE_EXIST_PANIC_WAITRECV);
-                
-                // set zero missed
-                o->num_missed = 0;
-                
-                // set state panic
-                o->state = STATE_EXIST_PANIC;
-                return;
-            }
-            
-            // set timer
-            BReactor_SetTimerAfter(o->reactor, &o->timer, BARPPROBE_EXIST_WAITRECV);
-        } break;
-        
-        case STATE_EXIST_PANIC: {
-            ASSERT(o->num_missed >= 0)
-            ASSERT(o->num_missed < BARPPROBE_EXIST_PANIC_NUM_NOREPLY)
-            
-            // increment missed
-            o->num_missed++;
-            
-            // all missed?
-            if (o->num_missed == BARPPROBE_EXIST_PANIC_NUM_NOREPLY) {
-                // set timer
-                BReactor_SetTimerAfter(o->reactor, &o->timer, BARPPROBE_NOEXIST_WAITRECV);
-                
-                // set state panic
-                o->state = STATE_NOEXIST;
-                
-                // report noexist
-                o->handler(o->user, BARPPROBE_EVENT_NOEXIST);
-                return;
-            }
-            
-            // set timer
-            BReactor_SetTimerAfter(o->reactor, &o->timer, BARPPROBE_EXIST_PANIC_WAITRECV);
-        } break;
-    }
-}
-
-int BArpProbe_Init (BArpProbe *o, const char *ifname, uint32_t addr, BReactor *reactor, void *user, BArpProbe_handler handler)
-{
-    ASSERT(ifname)
-    ASSERT(handler)
-    
-    // init arguments
-    o->addr = addr;
-    o->reactor = reactor;
-    o->user = user;
-    o->handler = handler;
-    
-    // get interface information
-    int if_mtu;
-    int if_index;
-    if (!badvpn_get_iface_info(ifname, o->if_mac, &if_mtu, &if_index)) {
-        BLog(BLOG_ERROR, "failed to get interface information");
-        goto fail0;
-    }
-    
-    uint8_t *if_mac = o->if_mac;
-    BLog(BLOG_INFO, "if_mac=%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8" if_mtu=%d if_index=%d",
-         if_mac[0], if_mac[1], if_mac[2], if_mac[3], if_mac[4], if_mac[5], if_mtu, if_index);
-    
-    // check MTU
-    if (if_mtu < sizeof(struct arp_packet)) {
-        BLog(BLOG_ERROR, "MTU is too small for ARP !?!");
-        goto fail0;
-    }
-    
-    // init dgram
-    if (!BDatagram_Init(&o->dgram, BADDR_TYPE_PACKET, o->reactor, o, (BDatagram_handler)dgram_handler)) {
-        BLog(BLOG_ERROR, "BDatagram_Init failed");
-        goto fail0;
-    }
-    
-    // bind dgram
-    BAddr bind_addr;
-    BAddr_InitPacket(&bind_addr, hton16(ETHERTYPE_ARP), if_index, BADDR_PACKET_HEADER_TYPE_ETHERNET, BADDR_PACKET_PACKET_TYPE_HOST, if_mac);
-    if (!BDatagram_Bind(&o->dgram, bind_addr)) {
-        BLog(BLOG_ERROR, "BDatagram_Bind failed");
-        goto fail1;
-    }
-    
-    // set dgram send addresses
-    BAddr dest_addr;
-    uint8_t broadcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-    BAddr_InitPacket(&dest_addr, hton16(ETHERTYPE_ARP), if_index, BADDR_PACKET_HEADER_TYPE_ETHERNET, BADDR_PACKET_PACKET_TYPE_BROADCAST, broadcast_mac);
-    BIPAddr local_addr;
-    BIPAddr_InitInvalid(&local_addr);
-    BDatagram_SetSendAddrs(&o->dgram, dest_addr, local_addr);
-    
-    // init send interface
-    BDatagram_SendAsync_Init(&o->dgram, sizeof(struct arp_packet));
-    o->send_if = BDatagram_SendAsync_GetIf(&o->dgram);
-    PacketPassInterface_Sender_Init(o->send_if, (PacketPassInterface_handler_done)send_if_handler_done, o);
-    
-    // set not sending
-    o->send_sending = 0;
-    
-    // init recv interface
-    BDatagram_RecvAsync_Init(&o->dgram, sizeof(struct arp_packet));
-    o->recv_if = BDatagram_RecvAsync_GetIf(&o->dgram);
-    PacketRecvInterface_Receiver_Init(o->recv_if, (PacketRecvInterface_handler_done)recv_if_handler_done, o);
-    
-    // init timer
-    BTimer_Init(&o->timer, 0, (BTimer_handler)timer_handler, o);
-    
-    // receive first packet
-    PacketRecvInterface_Receiver_Recv(o->recv_if, (uint8_t *)&o->recv_packet);
-    
-    // send request
-    send_request(o);
-    
-    // set timer
-    BReactor_SetTimerAfter(o->reactor, &o->timer, BARPPROBE_INITIAL_WAITRECV);
-    
-    // set zero missed
-    o->num_missed = 0;
-    
-    // set state initial
-    o->state = STATE_INITIAL;
-    
-    DebugError_Init(&o->d_err, BReactor_PendingGroup(o->reactor));
-    DebugObject_Init(&o->d_obj);
-    return 1;
-    
-fail1:
-    BDatagram_Free(&o->dgram);
-fail0:
-    return 0;
-}
-
-void BArpProbe_Free (BArpProbe *o)
-{
-    DebugObject_Free(&o->d_obj);
-    DebugError_Free(&o->d_err);
-    
-    // free timer
-    BReactor_RemoveTimer(o->reactor, &o->timer);
-    
-    // free recv interface
-    BDatagram_RecvAsync_Free(&o->dgram);
-    
-    // free send interface
-    BDatagram_SendAsync_Free(&o->dgram);
-    
-    // free dgram
-    BDatagram_Free(&o->dgram);
-}
diff --git a/external/badvpn_dns/arpprobe/BArpProbe.h b/external/badvpn_dns/arpprobe/BArpProbe.h
deleted file mode 100644
index 2ec3ffa..0000000
--- a/external/badvpn_dns/arpprobe/BArpProbe.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * @file BArpProbe.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BADVPN_BARPPROBE_H
-#define BADVPN_BARPPROBE_H
-
-#include <stdint.h>
-
-#include <misc/debug.h>
-#include <misc/debugerror.h>
-#include <misc/arp_proto.h>
-#include <misc/ethernet_proto.h>
-#include <base/DebugObject.h>
-#include <system/BDatagram.h>
-#include <system/BReactor.h>
-
-#define BARPPROBE_INITIAL_WAITRECV 1000
-#define BARPPROBE_INITIAL_NUM_ATTEMPTS 6
-#define BARPPROBE_NOEXIST_WAITRECV 15000
-#define BARPPROBE_EXIST_WAITSEND 15000
-#define BARPPROBE_EXIST_WAITRECV 10000
-#define BARPPROBE_EXIST_NUM_NOREPLY 2
-#define BARPPROBE_EXIST_PANIC_WAITRECV 1000
-#define BARPPROBE_EXIST_PANIC_NUM_NOREPLY 6
-
-#define BARPPROBE_EVENT_EXIST 1
-#define BARPPROBE_EVENT_NOEXIST 2
-#define BARPPROBE_EVENT_ERROR 3
-
-typedef void (*BArpProbe_handler) (void *user, int event);
-
-typedef struct {
-    uint32_t addr;
-    BReactor *reactor;
-    void *user;
-    BArpProbe_handler handler;
-    BDatagram dgram;
-    uint8_t if_mac[6];
-    PacketPassInterface *send_if;
-    int send_sending;
-    struct arp_packet send_packet;
-    PacketRecvInterface *recv_if;
-    struct arp_packet recv_packet;
-    BTimer timer;
-    int state;
-    int num_missed;
-    DebugError d_err;
-    DebugObject d_obj;
-} BArpProbe;
-
-int BArpProbe_Init (BArpProbe *o, const char *ifname, uint32_t addr, BReactor *reactor, void *user, BArpProbe_handler handler) WARN_UNUSED;
-void BArpProbe_Free (BArpProbe *o);
-
-#endif
diff --git a/external/badvpn_dns/arpprobe/CMakeLists.txt b/external/badvpn_dns/arpprobe/CMakeLists.txt
deleted file mode 100644
index a090f10..0000000
--- a/external/badvpn_dns/arpprobe/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
-badvpn_add_library(arpprobe "base;system;flow" "" BArpProbe.c)
diff --git a/external/badvpn_dns/badvpn.7 b/external/badvpn_dns/badvpn.7
deleted file mode 100644
index c421a35..0000000
--- a/external/badvpn_dns/badvpn.7
+++ /dev/null
@@ -1,324 +0,0 @@
-.TH badvpn 7 "6 October 2010"
-.SH NAME
-BadVPN - peer-to-peer VPN system
-.SH DESCRIPTION
-.P
-BadVPN is a peer-to-peer VPN system. It provides a Layer 2 (Ethernet) network between
-the peers (VPN network nodes). The peers connect to a central server which acts as a chat
-server for them to establish direct connections between each other (data connections).
-These connections are used for transferring network data (Ethernet frames).
-.SS "Features"
-.P
-.B "Data connections"
-.P
-Peers can transfer network data either over UDP or TCP. For both there are ways of
-securing the data (see below).
-.P
-.B "IPv6 support"
-.P
-IPv6 can be used for both server connections and data connections, alongside with IPv4.
-Additionally, both can be combined to allow gradual migration to IPv6.
-.P
-.B "Address selection"
-.P
-Because NATs and firewalls are widespread, it is harder for peer-to-peer services to operate.
-In general, for two computers to be able to communicate, one computer must
-.I bind
-to one of its addresses, and the other computer must
-.I connect
-to the computer that binded (both for TCP and UDP). In a network with point-to-point
-connectivity, the connecting computer can connect to the same address as the binding computer
-bound to, so it is sufficient for the binding computer to send its address to the connecting
-computer. However, NATs and firewalls break point-to-point connectivity. When a network is
-behind a NAT, it is, by default, impossible for computers outside of that network to connect
-to computers inside the network. This is because computers inside the network have no externally
-visible IP address, and only communicate with the outside world through the external IP address
-of the NAT router. It is however possible to manually configure the NAT router to
-.I forward
-a specific port number on its external IP address to a specific computer inside the network.
-This makes it possible for a computer outside of the network to connect to a computer inside
-a network, however, it must connect to the external address of the NAT router (rather than
-the address the computer inside bound to, which is its internal address). So there needs
-to be some way for the connecting peer to know what address to connect to.
-.P
-BadVPN solves this problem with so-called
-.IR "address scopes" "."
-The peer that binds must have a list of external addresses for each address it can bind to,
-possibly ordered from best to worst. Each external address has its scope name. A scope name
-represents part of a network from which an external address can be reached. On the other hand,
-the peer that connects must have a list of scopes which it can reach. When a peer binds to an
-address, it sends the other peer a list of external addresses along with scope names. That peer
-than chooses the first external address whose scope it recognizes and attempts to connect to it
-(if there is one).
-.P
-BadVPN also allows a peer to have multiple addresses for binding to. It is possible to specify
-both an IPv4 and an IPv6 address to work in a multi-protocol environment.
-.P
-.B "Relaying"
-.P
-BadVPN can be configured to allow pairs of peers that cannot communicate directly (i.e. because of
-NATs or firewalls) to relay network data through a third peer. Relaying is only attempted if
-none of the two peers recognize any of the other peer's external addresses (or there are none).
-For relaying to work, for each of the two peers (P1, other one P2) there must be at least one
-third peer (R) that P1 it is allowed to relay through and can communicate directly with, and all
-such peers R must be able to communicate directly with P2.
-.P
-.B "IGMP snooping"
-.P
-BadVPN nodes perform IGMP snooping in order to efficiently deliver multicast frames. For example,
-this makes it possible to use BadVPN as a tunnel into an IPTV network of an Internet Service Provider
-for you to watch TV from wherever you want (given sufficient link quality).
-.P
-.B "Code quality"
-.P
-BadVPN has great focus on code quality and reliability. BadVPN is written in the C programming
-language. It is a single-threaded event-driven program. This allows for low resource usage and
-fast response times. Even though C is a relatively low-level language, the programs are made of
-small, highly cohesive and loosely coupled modules that are combined into a complete program on
-a high level. Modules are accesed and communicate through small, simple and to-the-point interfaces.
-It utilizes a flow-based design which greatly simplifies processing of data and input and output
-of the programs.
-.SS "Security features"
-.P
-BadVPN contains many security features, all of which are optional. The included security
-features are described here.
-.P
-.B TLS for client-server connections
-.P
-It is possible for the peers to communicate with the chat server securely with TLS. It is
-highly recommended that this feature is used if any security whatsoever is needed. Not
-using it renders all other security features useless, since clients exchange keys
-unencrypted via the server. When enabled, the chat server requires each client to identify
-itself with a certificate.
-.P
-BadVPN uses Mozilla's NSS library for TLS support. This means that the required certificates
-and keys must be available in a NSS database. The database and certificates can be
-generated with the
-.B certutil
-command. See the examples section on how to generate and distribute the certificates.
-.P
-.B TLS for peer messaging
-.P
-If TLS is being used for client-server connections, it will also be used between each pair of
-peers communicating via the server, on top of the TLS connections to the server. This secures
-the messages from the server itself. It is important because the messages may include
-encryption keys and other private data.
-.P
-.B TLS for TCP data connections
-.P
-If TCP is used for data connections between the peers, the data connections can be secured
-with TLS. This requires using TLS for client-server connections. The clients need to trust
-each others' certificates to be able to connect. Additionally, each client must identify to
-its peers with the same certificates it used for connecting to the server.
-.P
-.B Encryption for UDP data connections
-.P
-If UDP is used for data connections, it is possible for each pair of peers to encrypt their
-UDP packets with a symmetric block cipher. Note that the encryption keys are transmitted
-through the server unencrypted, so for this to be useful, server connections must be secured
-with TLS. The encryption aims to prevent third parties from seeing the real contents of
-the network data being transfered.
-.P
-.B Hashes for UDP data connections
-.P
-If UDP is used for data connections, it is possible to include hashes in packets. Note that
-hashes are only useful together with encryption. If enabled, the hash is calculated on the
-packet with the hash field zeroed and then written to the hash field. Hashes are calculated
-and included before encryption (if enabled). Combined with encryption, hashes aim to prevent
-third parties from tampering with the packets and injecting them into the network.
-.P
-.B One-time passwords for UDP data connections
-.P
-If UDP is used for data connections, it is possible to include one-time passwords in packets.
-Note that for this to be useful, server connections must be secured with TLS.
-One-time passwords are generated from a seed value by encrypting zero data with a block cipher.
-The seed contains the encryption key for the block cipher and the initialization vector.
-Only a fixed number of passwords are used from a single seed. The peers exchange seeds through
-the server. One-time passwords aim to prevent replay attacks.
-.P
-.B Control over peer communication
-.P
-It is possible to instruct the chat server to only allow certain peers to communicate. This
-will break end-to-end connectivity in the virtual network. It is useful in certain cases
-to improve security, for example when the VPN is used only to allow clients to securely connect
-to a central service.
-.SH "EXAMPLES"
-.SS "Setting up certificates"
-.P
-If you want to use TLS for server connections (recommended), the server and all the peers will
-need certificates. This section explains how to generate and distribute the certificates using
-NSS command line tools.
-.P
-.B Setting up the Certificate Authority (CA)
-.P
-On the system that will host the CA, create a NSS database for the CA and generate a CA certificate
-valid for 24 months:
-.P
-vpnca $ certutil -d sql:/home/vpnca/nssdb -N
-.br
-vpnca $ certutil -d sql:/home/vpnca/nssdb -S -n "vpnca" -s "CN=vpnca" -t "TC,," -x -2 -v 24
-.br
-> Is this a CA certificate [y/N]? y
-.br
-> Enter the path length constraint, enter to skip [<0 for unlimited path]: > -1
-.br
-> Is this a critical extension [y/N]? n
-.P
-Export the public CA certificate (this file is public):
-.P
-vpnca $ certutil -d sql:/home/vpnca/nssdb -L -n vpnca -a > ca.pem
-.P
-.B Setting up the server certificate
-.P
-On the CA system, generate a certificate for the server valid for 24 months, with TLS server usage context:
-.P
-vpnca $ certutil -d sql:/home/vpnca/nssdb -S -n "<insert_server_name>" -s "CN=<insert_server_name>" -c "vpnca" -t ",," -2 -6 -v 24
-.br
-> 0
-.br
-> -1
-.br
-> Is this a critical extension [y/N]? n
-.br
-> Is this a CA certificate [y/N]? n
-.br
-> Enter the path length constraint, enter to skip [<0 for unlimited path]: >
-.br
-> Is this a critical extension [y/N]? n
-.P
-Export the server certificate to a PKCS#12 file (this file must be kept secret):
-.P
-vpnca $ pk12util -d sql:/home/vpnca/nssdb -o server.p12 -n "<insert_server_name>"
-.P
-On the system that will run the server, create a NSS database and import the CA certificate
-and the server cerificate:
-.P
-vpnserver $ certutil -d sql:/home/vpnserver/nssdb -N
-.br
-vpnserver $ certutil -d sql:/home/vpnserver/nssdb -A -t "CT,," -n "vpnca" -i /path/to/ca.pem
-.br
-vpnserver $ pk12util -d sql:/home/vpnserver/nssdb -i /path/to/server.p12
-.P
-.B Setting up peer certificates
-.P
-On the CA system, generate a certificate for the peer valid for 24 months, with TLS client and
-TLS server usage contexts:
-.P
-vpnca $ certutil -d sql:/home/vpnca/nssdb -S -n "peer-<insert_name>" -s "CN=peer-<insert_name>" -c "vpnca" -t ",," -2 -6 -v 24
-.br
-> 0
-.br
-> 1
-.br
-> -1
-.br
-> Is this a critical extension [y/N]? n
-.br
-> Is this a CA certificate [y/N]? n
-.br
-> Enter the path length constraint, enter to skip [<0 for unlimited path]: >
-.br
-> Is this a critical extension [y/N]? n
-.P
-Export the peer certificate to a PKCS#12 file (this file must be kept secret):
-.P
-vpnca $ pk12util -d sql:/home/vpnca/nssdb -o peer-<insert_name>.p12 -n "peer-<insert_name>"
-.P
-On the system that will run the VPN client, create a NSS database and import the CA certificate
-and the peer cerificate:
-.P
-vpnclient $ certutil -d sql:/home/vpnclient/nssdb -N
-.br
-vpnclient $ certutil -d sql:/home/vpnclient/nssdb -A -t "CT,," -n "vpnca" -i /path/to/ca.pem
-.br
-vpnclient $ pk12util -d sql:/home/vpnclient/nssdb -i /path/to/peer-<insert_name>.p12
-.SS "Setting up TAP devices"
-.P
-You need to create and configure TAP devices on all computers that will participate in the virtual network
-(i.e. run the client program). See
-.BR badvpn-client (8),
-section `TAP DEVICE CONFIGURATION` for details.
-.SS "Example: Local IPv4 network, UDP transport, zero security"
-.P
-.B Starting the server:
-.P
-badvpn-server --listen-addr 0.0.0.0:7000
-.P
-.B Starting the peers:
-.P
-badvpn-client
-.RS
---server-addr <insert_server_local_address>:7000
-.br
---transport-mode udp --encryption-mode none --hash-mode none
-.br
---scope local1
-.br
---bind-addr 0.0.0.0:8000 --num-ports 30 --ext-addr {server_reported}:8000 local1
-.br
---tapdev tap0
-.RE
-.SS "Example: Adding TLS and UDP security"
-.P
-.B Starting the server (other options as above):
-.P
-badvpn-server ...
-.RS
---ssl --nssdb sql:/home/vpnserver/nssdb --server-cert-name "<insert_server_name>"
-.RE
-.P
-.B Starting the peers (other options as above):
-.P
-badvpn-client ...
-.RS
---ssl --nssdb sql:/home/vpnclient/nssdb --client-cert-name "peer-<insert_name>"
-.br
---encryption-mode blowfish --hash-mode md5 --otp blowfish 3000 2000
-.RE
-.SS "Example: Multiple local networks behind NATs, all connected to the Internet"
-.P
-For each peer in the existing local network, configure the NAT router to forward its
-range of ports to it (assuming their port ranges do not overlap). The clients also need
-to know the external IP address of the NAT router. If you don't have a static one,
-you'll need to discover it before starting the clients. Also forward the server port to
-the server.
-.P
-.B Starting the peers in the local network (other options as above):
-.P
-badvpn-client
-.RS
-.RB "..."
-.br
---scope internet
-.br
-.RB "..."
-.br
---ext-addr <insert_NAT_routers_external_IP>:<insert_start_of_forwarded_port_range> internet
-.br
-.RB "..."
-.RE
-.P
-The --ext-addr option applies to the previously specified --bind-addr option, and must come after
-the first --ext-addr option which specifies a local address.
-.P
-Now perform a similar setup in some other local network behind a NAT. However:
-.br
-- Don't set up a new server, instead make the peers connect to the existing server in the first
-local network.
-.br
-- You can't use {server_reported} for the local address --ext-addr options, because the server
-would report the NAT router's external address rather than the peer's internal address. Instead
-each peer has to know its internal IP address.
-.br
-- Use a different scope name for it, e.g. "local2" instead of "local1".
-.P
-If setup correctly, all peers will be able to communicate: those in the same local network will
-communicate directly through local addresses, and those in different local networks will
-communicate through the Internet.
-.SH "PROTOCOL"
-The protocols used in BadVPN are described in the source code in the protocol/ directory.
-.SH "SEE ALSO"
-.BR badvpn-server (8),
-.BR badvpn-client (8)
-.SH AUTHORS
-Ambroz Bizjak <ambrop7 at gmail.com>
diff --git a/external/badvpn_dns/base/BLog.c b/external/badvpn_dns/base/BLog.c
deleted file mode 100644
index 94242d5..0000000
--- a/external/badvpn_dns/base/BLog.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * @file BLog.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stddef.h>
-
-#include "BLog.h"
-
-#ifndef BADVPN_PLUGIN
-
-struct _BLog_channel blog_channel_list[] = {
-#include <generated/blog_channels_list.h>
-};
-
-struct _BLog_global blog_global = {
-    #ifndef NDEBUG
-    0
-    #endif
-};
-
-#endif
-
-// keep in sync with level numbers in BLog.h!
-static char *level_names[] = { NULL, "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG" };
-
-static void stdout_log (int channel, int level, const char *msg)
-{
-    fprintf(stdout, "%s(%s): %s\n", level_names[level], blog_global.channels[channel].name, msg);
-}
-
-static void stderr_log (int channel, int level, const char *msg)
-{
-    fprintf(stderr, "%s(%s): %s\n", level_names[level], blog_global.channels[channel].name, msg);
-}
-
-static void stdout_stderr_free (void)
-{
-}
-
-void BLog_InitStdout (void)
-{
-    BLog_Init(stdout_log, stdout_stderr_free);
-}
-
-void BLog_InitStderr (void)
-{
-    BLog_Init(stderr_log, stdout_stderr_free);
-}
-
-// ==== PSIPHON ====
-#ifdef PSIPHON
-
-void PsiphonLog(const char *level, const char *channel, const char *msg);
-
-static void psiphon_log (int channel, int level, const char *msg)
-{
-    PsiphonLog(level_names[level], blog_global.channels[channel].name, msg);
-}
-
-static void psiphon_free (void)
-{
-}
-
-void BLog_InitPsiphon (void)
-{
-    BLog_Init(psiphon_log, psiphon_free);
-}
-
-#endif
-// ==== PSIPHON ====
diff --git a/external/badvpn_dns/base/BLog.h b/external/badvpn_dns/base/BLog.h
deleted file mode 100644
index dd2e4d0..0000000
--- a/external/badvpn_dns/base/BLog.h
+++ /dev/null
@@ -1,402 +0,0 @@
-/**
- * @file BLog.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * A global object for logging.
- */
-
-#ifndef BADVPN_BLOG_H
-#define BADVPN_BLOG_H
-
-#include <stdarg.h>
-#include <string.h>
-
-#include <misc/debug.h>
-#include <base/BMutex.h>
-
-// auto-generated channel numbers and number of channels
-#include <generated/blog_channels_defines.h>
-
-// keep in sync with level names in BLog.c!
-#define BLOG_ERROR 1
-#define BLOG_WARNING 2
-#define BLOG_NOTICE 3
-#define BLOG_INFO 4
-#define BLOG_DEBUG 5
-
-#define BLog(...) BLog_LogToChannel(BLOG_CURRENT_CHANNEL, __VA_ARGS__)
-#define BContextLog(context, ...) BLog_ContextLog((context), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
-#define BLOG_CCCC(context) BLog_MakeChannelContext((context), BLOG_CURRENT_CHANNEL)
-
-typedef void (*_BLog_log_func) (int channel, int level, const char *msg);
-typedef void (*_BLog_free_func) (void);
-
-struct _BLog_channel {
-    const char *name;
-    int loglevel;
-};
-
-struct _BLog_global {
-    #ifndef NDEBUG
-    int initialized; // initialized statically
-    #endif
-    struct _BLog_channel channels[BLOG_NUM_CHANNELS];
-    _BLog_log_func log_func;
-    _BLog_free_func free_func;
-    BMutex mutex;
-#ifndef NDEBUG
-    int logging;
-#endif
-    char logbuf[2048];
-    int logbuf_pos;
-};
-
-extern struct _BLog_channel blog_channel_list[];
-extern struct _BLog_global blog_global;
-
-typedef void (*BLog_logfunc) (void *);
-
-typedef struct {
-    BLog_logfunc logfunc;
-    void *logfunc_user;
-} BLogContext;
-
-typedef struct {
-    BLogContext context;
-    int channel;
-} BLogChannelContext;
-
-static int BLogGlobal_GetChannelByName (const char *channel_name);
-
-static void BLog_Init (_BLog_log_func log_func, _BLog_free_func free_func);
-static void BLog_Free (void);
-static void BLog_SetChannelLoglevel (int channel, int loglevel);
-static int BLog_WouldLog (int channel, int level);
-static void BLog_Begin (void);
-static void BLog_AppendVarArg (const char *fmt, va_list vl);
-static void BLog_Append (const char *fmt, ...);
-static void BLog_AppendBytes (const char *data, size_t len);
-static void BLog_Finish (int channel, int level);
-static void BLog_LogToChannelVarArg (int channel, int level, const char *fmt, va_list vl);
-static void BLog_LogToChannel (int channel, int level, const char *fmt, ...);
-static void BLog_LogViaFuncVarArg (BLog_logfunc func, void *arg, int channel, int level, const char *fmt, va_list vl);
-static void BLog_LogViaFunc (BLog_logfunc func, void *arg, int channel, int level, const char *fmt, ...);
-static BLogContext BLog_RootContext (void);
-static BLogContext BLog_MakeContext (BLog_logfunc logfunc, void *logfunc_user);
-static void BLog_ContextLogVarArg (BLogContext context, int channel, int level, const char *fmt, va_list vl);
-static void BLog_ContextLog (BLogContext context, int channel, int level, const char *fmt, ...);
-static BLogChannelContext BLog_MakeChannelContext (BLogContext context, int channel);
-static void BLog_ChannelContextLogVarArg (BLogChannelContext ccontext, int level, const char *fmt, va_list vl);
-static void BLog_ChannelContextLog (BLogChannelContext ccontext, int level, const char *fmt, ...);
-
-void BLog_InitStdout (void);
-void BLog_InitStderr (void);
-
-// PSIPHON
-void BLog_InitPsiphon (void);
-
-int BLogGlobal_GetChannelByName (const char *channel_name)
-{
-    int i;
-    for (i = 0; i < BLOG_NUM_CHANNELS; i++) {
-        if (!strcmp(blog_channel_list[i].name, channel_name)) {
-            return i;
-        }
-    }
-    
-    return -1;
-}
-
-void BLog_Init (_BLog_log_func log_func, _BLog_free_func free_func)
-{
-    ASSERT(!blog_global.initialized)
-    
-    #ifndef NDEBUG
-    blog_global.initialized = 1;
-    #endif
-    
-    // initialize channels
-    memcpy(blog_global.channels, blog_channel_list, BLOG_NUM_CHANNELS * sizeof(struct _BLog_channel));
-    
-    blog_global.log_func = log_func;
-    blog_global.free_func = free_func;
-#ifndef NDEBUG
-    blog_global.logging = 0;
-#endif
-    blog_global.logbuf_pos = 0;
-    blog_global.logbuf[0] = '\0';
-    
-    ASSERT_FORCE(BMutex_Init(&blog_global.mutex))
-}
-
-void BLog_Free (void)
-{
-    ASSERT(blog_global.initialized)
-#ifndef NDEBUG
-    ASSERT(!blog_global.logging)
-#endif
-    
-    BMutex_Free(&blog_global.mutex);
-    
-    #ifndef NDEBUG
-    blog_global.initialized = 0;
-    #endif
-    
-    blog_global.free_func();
-}
-
-void BLog_SetChannelLoglevel (int channel, int loglevel)
-{
-    ASSERT(blog_global.initialized)
-    ASSERT(channel >= 0 && channel < BLOG_NUM_CHANNELS)
-    ASSERT(loglevel >= 0 && loglevel <= BLOG_DEBUG)
-    
-    blog_global.channels[channel].loglevel = loglevel;
-}
-
-int BLog_WouldLog (int channel, int level)
-{
-    ASSERT(blog_global.initialized)
-    ASSERT(channel >= 0 && channel < BLOG_NUM_CHANNELS)
-    ASSERT(level >= BLOG_ERROR && level <= BLOG_DEBUG)
-    
-    return (level <= blog_global.channels[channel].loglevel);
-}
-
-void BLog_Begin (void)
-{
-    ASSERT(blog_global.initialized)
-    
-    BMutex_Lock(&blog_global.mutex);
-    
-#ifndef NDEBUG
-    ASSERT(!blog_global.logging)
-    blog_global.logging = 1;
-#endif
-}
-
-void BLog_AppendVarArg (const char *fmt, va_list vl)
-{
-    ASSERT(blog_global.initialized)
-#ifndef NDEBUG
-    ASSERT(blog_global.logging)
-#endif
-    ASSERT(blog_global.logbuf_pos >= 0)
-    ASSERT(blog_global.logbuf_pos < sizeof(blog_global.logbuf))
-    
-    int w = vsnprintf(blog_global.logbuf + blog_global.logbuf_pos, sizeof(blog_global.logbuf) - blog_global.logbuf_pos, fmt, vl);
-    
-    if (w >= sizeof(blog_global.logbuf) - blog_global.logbuf_pos) {
-        blog_global.logbuf_pos = sizeof(blog_global.logbuf) - 1;
-    } else {
-        blog_global.logbuf_pos += w;
-    }
-}
-
-void BLog_Append (const char *fmt, ...)
-{
-    ASSERT(blog_global.initialized)
-#ifndef NDEBUG
-    ASSERT(blog_global.logging)
-#endif
-    
-    va_list vl;
-    va_start(vl, fmt);
-    BLog_AppendVarArg(fmt, vl);
-    va_end(vl);
-}
-
-void BLog_AppendBytes (const char *data, size_t len)
-{
-    ASSERT(blog_global.initialized)
-#ifndef NDEBUG
-    ASSERT(blog_global.logging)
-#endif
-    ASSERT(blog_global.logbuf_pos >= 0)
-    ASSERT(blog_global.logbuf_pos < sizeof(blog_global.logbuf))
-    
-    size_t avail = (sizeof(blog_global.logbuf) - 1) - blog_global.logbuf_pos;
-    len = (len > avail ? avail : len);
-    
-    memcpy(blog_global.logbuf + blog_global.logbuf_pos, data, len);
-    blog_global.logbuf_pos += len;
-    blog_global.logbuf[blog_global.logbuf_pos] = '\0';
-}
-
-void BLog_Finish (int channel, int level)
-{
-    ASSERT(blog_global.initialized)
-#ifndef NDEBUG
-    ASSERT(blog_global.logging)
-#endif
-    ASSERT(channel >= 0 && channel < BLOG_NUM_CHANNELS)
-    ASSERT(level >= BLOG_ERROR && level <= BLOG_DEBUG)
-    ASSERT(BLog_WouldLog(channel, level))
-    
-    ASSERT(blog_global.logbuf_pos >= 0)
-    ASSERT(blog_global.logbuf_pos < sizeof(blog_global.logbuf))
-    ASSERT(blog_global.logbuf[blog_global.logbuf_pos] == '\0')
-    
-    blog_global.log_func(channel, level, blog_global.logbuf);
-    
-#ifndef NDEBUG
-    blog_global.logging = 0;
-#endif
-    blog_global.logbuf_pos = 0;
-    blog_global.logbuf[0] = '\0';
-    
-    BMutex_Unlock(&blog_global.mutex);
-}
-
-void BLog_LogToChannelVarArg (int channel, int level, const char *fmt, va_list vl)
-{
-    ASSERT(blog_global.initialized)
-    ASSERT(channel >= 0 && channel < BLOG_NUM_CHANNELS)
-    ASSERT(level >= BLOG_ERROR && level <= BLOG_DEBUG)
-    
-    if (!BLog_WouldLog(channel, level)) {
-        return;
-    }
-    
-    BLog_Begin();
-    BLog_AppendVarArg(fmt, vl);
-    BLog_Finish(channel, level);
-}
-
-void BLog_LogToChannel (int channel, int level, const char *fmt, ...)
-{
-    ASSERT(blog_global.initialized)
-    ASSERT(channel >= 0 && channel < BLOG_NUM_CHANNELS)
-    ASSERT(level >= BLOG_ERROR && level <= BLOG_DEBUG)
-    
-    if (!BLog_WouldLog(channel, level)) {
-        return;
-    }
-    
-    va_list vl;
-    va_start(vl, fmt);
-    
-    BLog_Begin();
-    BLog_AppendVarArg(fmt, vl);
-    BLog_Finish(channel, level);
-    
-    va_end(vl);
-}
-
-void BLog_LogViaFuncVarArg (BLog_logfunc func, void *arg, int channel, int level, const char *fmt, va_list vl)
-{
-    ASSERT(blog_global.initialized)
-    ASSERT(channel >= 0 && channel < BLOG_NUM_CHANNELS)
-    ASSERT(level >= BLOG_ERROR && level <= BLOG_DEBUG)
-    
-    if (!BLog_WouldLog(channel, level)) {
-        return;
-    }
-    
-    BLog_Begin();
-    func(arg);
-    BLog_AppendVarArg(fmt, vl);
-    BLog_Finish(channel, level);
-}
-
-void BLog_LogViaFunc (BLog_logfunc func, void *arg, int channel, int level, const char *fmt, ...)
-{
-    ASSERT(blog_global.initialized)
-    ASSERT(channel >= 0 && channel < BLOG_NUM_CHANNELS)
-    ASSERT(level >= BLOG_ERROR && level <= BLOG_DEBUG)
-    
-    if (!BLog_WouldLog(channel, level)) {
-        return;
-    }
-    
-    va_list vl;
-    va_start(vl, fmt);
-    
-    BLog_Begin();
-    func(arg);
-    BLog_AppendVarArg(fmt, vl);
-    BLog_Finish(channel, level);
-    
-    va_end(vl);
-}
-
-static void BLog__root_logfunc (void *unused)
-{
-}
-
-static BLogContext BLog_RootContext (void)
-{
-    return BLog_MakeContext(BLog__root_logfunc, NULL);
-}
-
-static BLogContext BLog_MakeContext (BLog_logfunc logfunc, void *logfunc_user)
-{
-    ASSERT(logfunc)
-    
-    BLogContext context;
-    context.logfunc = logfunc;
-    context.logfunc_user = logfunc_user;
-    return context;
-}
-
-static void BLog_ContextLogVarArg (BLogContext context, int channel, int level, const char *fmt, va_list vl)
-{
-    BLog_LogViaFuncVarArg(context.logfunc, context.logfunc_user, channel, level, fmt, vl);
-}
-
-static void BLog_ContextLog (BLogContext context, int channel, int level, const char *fmt, ...)
-{
-    va_list vl;
-    va_start(vl, fmt);
-    BLog_ContextLogVarArg(context, channel, level, fmt, vl);
-    va_end(vl);
-}
-
-static BLogChannelContext BLog_MakeChannelContext (BLogContext context, int channel)
-{
-    BLogChannelContext ccontext;
-    ccontext.context = context;
-    ccontext.channel = channel;
-    return ccontext;
-}
-
-static void BLog_ChannelContextLogVarArg (BLogChannelContext ccontext, int level, const char *fmt, va_list vl)
-{
-    BLog_ContextLogVarArg(ccontext.context, ccontext.channel, level, fmt, vl);
-}
-
-static void BLog_ChannelContextLog (BLogChannelContext ccontext, int level, const char *fmt, ...)
-{
-    va_list vl;
-    va_start(vl, fmt);
-    BLog_ChannelContextLogVarArg(ccontext, level, fmt, vl);
-    va_end(vl);
-}
-
-#endif
diff --git a/external/badvpn_dns/base/BLog_syslog.c b/external/badvpn_dns/base/BLog_syslog.c
deleted file mode 100644
index d7a954b..0000000
--- a/external/badvpn_dns/base/BLog_syslog.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/**
- * @file BLog_syslog.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-#include <stdio.h>
-#include <syslog.h>
-
-#include <misc/debug.h>
-
-#include "BLog_syslog.h"
-
-static int resolve_facility (char *str, int *out)
-{
-    if (!strcmp(str, "authpriv")) {
-        *out = LOG_AUTHPRIV;
-    }
-    else if (!strcmp(str, "cron")) {
-        *out = LOG_CRON;
-    }
-    else if (!strcmp(str, "daemon")) {
-        *out = LOG_DAEMON;
-    }
-    else if (!strcmp(str, "ftp")) {
-        *out = LOG_FTP;
-    }
-    else if (!strcmp(str, "local0")) {
-        *out = LOG_LOCAL0;
-    }
-    else if (!strcmp(str, "local1")) {
-        *out = LOG_LOCAL1;
-    }
-    else if (!strcmp(str, "local2")) {
-        *out = LOG_LOCAL2;
-    }
-    else if (!strcmp(str, "local3")) {
-        *out = LOG_LOCAL3;
-    }
-    else if (!strcmp(str, "local4")) {
-        *out = LOG_LOCAL4;
-    }
-    else if (!strcmp(str, "local5")) {
-        *out = LOG_LOCAL5;
-    }
-    else if (!strcmp(str, "local6")) {
-        *out = LOG_LOCAL6;
-    }
-    else if (!strcmp(str, "local7")) {
-        *out = LOG_LOCAL7;
-    }
-    else if (!strcmp(str, "lpr")) {
-        *out = LOG_LPR;
-    }
-    else if (!strcmp(str, "mail")) {
-        *out = LOG_MAIL;
-    }
-    else if (!strcmp(str, "news")) {
-        *out = LOG_NEWS;
-    }
-    else if (!strcmp(str, "syslog")) {
-        *out = LOG_SYSLOG;
-    }
-    else if (!strcmp(str, "user")) {
-        *out = LOG_USER;
-    }
-    else if (!strcmp(str, "uucp")) {
-        *out = LOG_UUCP;
-    }
-    else {
-        return 0;
-    }
-    
-    return 1;
-}
-
-static int convert_level (int level)
-{
-    ASSERT(level >= BLOG_ERROR && level <= BLOG_DEBUG)
-    
-    switch (level) {
-        case BLOG_ERROR:
-            return LOG_ERR;
-        case BLOG_WARNING:
-            return LOG_WARNING;
-        case BLOG_NOTICE:
-            return LOG_NOTICE;
-        case BLOG_INFO:
-            return LOG_INFO;
-        case BLOG_DEBUG:
-            return LOG_DEBUG;
-        default:
-            ASSERT(0)
-            return 0;
-    }
-}
-
-static struct {
-    char ident[200];
-} syslog_global;
-
-static void syslog_log (int channel, int level, const char *msg)
-{
-    syslog(convert_level(level), "%s: %s", blog_global.channels[channel].name, msg);
-}
-
-static void syslog_free (void)
-{
-    closelog();
-}
-
-int BLog_InitSyslog (char *ident, char *facility_str)
-{
-    int facility;
-    if (!resolve_facility(facility_str, &facility)) {
-        return 0;
-    }
-    
-    snprintf(syslog_global.ident, sizeof(syslog_global.ident), "%s", ident);
-    
-    openlog(syslog_global.ident, 0, facility);
-    
-    BLog_Init(syslog_log, syslog_free);
-    
-    return 1;
-}
diff --git a/external/badvpn_dns/base/BLog_syslog.h b/external/badvpn_dns/base/BLog_syslog.h
deleted file mode 100644
index 1adf04e..0000000
--- a/external/badvpn_dns/base/BLog_syslog.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * @file BLog_syslog.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * BLog syslog backend.
- */
-
-#ifndef BADVPN_BLOG_SYSLOG_H
-#define BADVPN_BLOG_SYSLOG_H
-
-#include <misc/debug.h>
-#include <base/BLog.h>
-
-int BLog_InitSyslog (char *ident, char *facility) WARN_UNUSED;
-
-#endif
diff --git a/external/badvpn_dns/base/BMutex.h b/external/badvpn_dns/base/BMutex.h
deleted file mode 100644
index fbcbd05..0000000
--- a/external/badvpn_dns/base/BMutex.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * @file BMutex.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BADVPN_BMUTEX_H
-#define BADVPN_BMUTEX_H
-
-#if !defined(BADVPN_THREAD_SAFE) || (BADVPN_THREAD_SAFE != 0 && BADVPN_THREAD_SAFE != 1)
-#error BADVPN_THREAD_SAFE is not defined or incorrect
-#endif
-
-#if BADVPN_THREAD_SAFE
-#include <pthread.h>
-#endif
-
-#include <misc/debug.h>
-#include <base/DebugObject.h>
-
-typedef struct {
-#if BADVPN_THREAD_SAFE
-    pthread_mutex_t pthread_mutex;
-#endif
-    DebugObject d_obj;
-} BMutex;
-
-static int BMutex_Init (BMutex *o) WARN_UNUSED;
-static void BMutex_Free (BMutex *o);
-static void BMutex_Lock (BMutex *o);
-static void BMutex_Unlock (BMutex *o);
-
-static int BMutex_Init (BMutex *o)
-{
-#if BADVPN_THREAD_SAFE
-    if (pthread_mutex_init(&o->pthread_mutex, NULL) != 0) {
-        return 0;
-    }
-#endif
-    
-    DebugObject_Init(&o->d_obj);
-    return 1;
-}
-
-static void BMutex_Free (BMutex *o)
-{
-    DebugObject_Free(&o->d_obj);
-    
-#if BADVPN_THREAD_SAFE
-    int res = pthread_mutex_destroy(&o->pthread_mutex);
-    B_USE(res)
-    ASSERT(res == 0)
-#endif
-}
-
-static void BMutex_Lock (BMutex *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-#if BADVPN_THREAD_SAFE
-    int res = pthread_mutex_lock(&o->pthread_mutex);
-    B_USE(res)
-    ASSERT(res == 0)
-#endif
-}
-
-static void BMutex_Unlock (BMutex *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-#if BADVPN_THREAD_SAFE
-    int res = pthread_mutex_unlock(&o->pthread_mutex);
-    B_USE(res)
-    ASSERT(res == 0)
-#endif
-}
-
-#endif
diff --git a/external/badvpn_dns/base/BPending.c b/external/badvpn_dns/base/BPending.c
deleted file mode 100644
index 6711604..0000000
--- a/external/badvpn_dns/base/BPending.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/**
- * @file BPending.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stddef.h>
-
-#include <misc/debug.h>
-#include <misc/offset.h>
-
-#include "BPending.h"
-
-#include "BPending_list.h"
-#include <structure/SLinkedList_impl.h>
-
-void BPendingGroup_Init (BPendingGroup *g)
-{
-    // init jobs list
-    BPending__List_Init(&g->jobs);
-    
-    // init pending counter
-    DebugCounter_Init(&g->pending_ctr);
-    
-    // init debug object
-    DebugObject_Init(&g->d_obj);
-}
-
-void BPendingGroup_Free (BPendingGroup *g)
-{
-    DebugCounter_Free(&g->pending_ctr);
-    ASSERT(BPending__List_IsEmpty(&g->jobs))
-    DebugObject_Free(&g->d_obj);
-}
-
-int BPendingGroup_HasJobs (BPendingGroup *g)
-{
-    DebugObject_Access(&g->d_obj);
-    
-    return !BPending__List_IsEmpty(&g->jobs);
-}
-
-void BPendingGroup_ExecuteJob (BPendingGroup *g)
-{
-    ASSERT(!BPending__List_IsEmpty(&g->jobs))
-    DebugObject_Access(&g->d_obj);
-    
-    // get a job
-    BSmallPending *p = BPending__List_First(&g->jobs);
-    ASSERT(!BPending__ListIsRemoved(p))
-    ASSERT(p->pending)
-    
-    // remove from jobs list
-    BPending__List_RemoveFirst(&g->jobs);
-    
-    // set not pending
-    BPending__ListMarkRemoved(p);
-#ifndef NDEBUG
-    p->pending = 0;
-#endif
-    
-    // execute job
-    p->handler(p->user);
-    return;
-}
-
-BSmallPending * BPendingGroup_PeekJob (BPendingGroup *g)
-{
-    DebugObject_Access(&g->d_obj);
-    
-    return BPending__List_First(&g->jobs);
-}
-
-void BSmallPending_Init (BSmallPending *o, BPendingGroup *g, BSmallPending_handler handler, void *user)
-{
-    // init arguments
-    o->handler = handler;
-    o->user = user;
-    
-    // set not pending
-    BPending__ListMarkRemoved(o);
-#ifndef NDEBUG
-    o->pending = 0;
-#endif
-    
-    // increment pending counter
-    DebugCounter_Increment(&g->pending_ctr);
-    
-    // init debug object
-    DebugObject_Init(&o->d_obj);
-}
-
-void BSmallPending_Free (BSmallPending *o, BPendingGroup *g)
-{
-    DebugCounter_Decrement(&g->pending_ctr);
-    DebugObject_Free(&o->d_obj);
-    ASSERT(o->pending == !BPending__ListIsRemoved(o))
-    
-    // remove from jobs list
-    if (!BPending__ListIsRemoved(o)) {
-        BPending__List_Remove(&g->jobs, o);
-    }
-}
-
-void BSmallPending_SetHandler (BSmallPending *o, BSmallPending_handler handler, void *user)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    // set handler
-    o->handler = handler;
-    o->user = user;
-}
-
-void BSmallPending_Set (BSmallPending *o, BPendingGroup *g)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->pending == !BPending__ListIsRemoved(o))
-    
-    // remove from jobs list
-    if (!BPending__ListIsRemoved(o)) {
-        BPending__List_Remove(&g->jobs, o);
-    }
-    
-    // insert to jobs list
-    BPending__List_Prepend(&g->jobs, o);
-    
-    // set pending
-#ifndef NDEBUG
-    o->pending = 1;
-#endif
-}
-
-void BSmallPending_Unset (BSmallPending *o, BPendingGroup *g)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->pending == !BPending__ListIsRemoved(o))
-    
-    if (!BPending__ListIsRemoved(o)) {
-        // remove from jobs list
-        BPending__List_Remove(&g->jobs, o);
-        
-        // set not pending
-        BPending__ListMarkRemoved(o);
-#ifndef NDEBUG
-        o->pending = 0;
-#endif
-    }
-}
-
-int BSmallPending_IsSet (BSmallPending *o)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->pending == !BPending__ListIsRemoved(o))
-    
-    return !BPending__ListIsRemoved(o);
-}
-
-void BPending_Init (BPending *o, BPendingGroup *g, BPending_handler handler, void *user)
-{
-    BSmallPending_Init(&o->base, g, handler, user);
-    o->g = g;
-}
-
-void BPending_Free (BPending *o)
-{
-    BSmallPending_Free(&o->base, o->g);
-}
-
-void BPending_Set (BPending *o)
-{
-    BSmallPending_Set(&o->base, o->g);
-}
-
-void BPending_Unset (BPending *o)
-{
-    BSmallPending_Unset(&o->base, o->g);
-}
-
-int BPending_IsSet (BPending *o)
-{
-    return BSmallPending_IsSet(&o->base);
-}
diff --git a/external/badvpn_dns/base/BPending.h b/external/badvpn_dns/base/BPending.h
deleted file mode 100644
index 07644be..0000000
--- a/external/badvpn_dns/base/BPending.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/**
- * @file BPending.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Module for managing a queue of jobs pending execution.
- */
-
-#ifndef BADVPN_BPENDING_H
-#define BADVPN_BPENDING_H
-
-#include <stdint.h>
-
-#include <misc/debugcounter.h>
-#include <structure/SLinkedList.h>
-#include <base/DebugObject.h>
-
-struct BSmallPending_s;
-
-#include "BPending_list.h"
-#include <structure/SLinkedList_decl.h>
-
-/**
- * Job execution handler.
- * It is guaranteed that the associated {@link BSmallPending} object was
- * in set state.
- * The {@link BSmallPending} object enters not set state before the handler
- * is called.
- * 
- * @param user as in {@link BSmallPending_Init}
- */
-typedef void (*BSmallPending_handler) (void *user);
-
-/**
- * Job execution handler.
- * It is guaranteed that the associated {@link BPending} object was
- * in set state.
- * The {@link BPending} object enters not set state before the handler
- * is called.
- * 
- * @param user as in {@link BPending_Init}
- */
-typedef void (*BPending_handler) (void *user);
-
-/**
- * Object that contains a list of jobs pending execution.
- */
-typedef struct {
-    BPending__List jobs;
-    DebugCounter pending_ctr;
-    DebugObject d_obj;
-} BPendingGroup;
-
-/**
- * Object for queuing a job for execution.
- */
-typedef struct BSmallPending_s {
-    BPending_handler handler;
-    void *user;
-    BPending__ListNode pending_node; // optimization: if not pending, .next is this
-#ifndef NDEBUG
-    uint8_t pending;
-#endif
-    DebugObject d_obj;
-} BSmallPending;
-
-/**
- * Object for queuing a job for execution. This is a convenience wrapper
- * around {@link BSmallPending} with an extra field to remember the
- * {@link BPendingGroup} being used.
- */
-typedef struct {
-    BSmallPending base;
-    BPendingGroup *g;
-} BPending;
-
-/**
- * Initializes the object.
- * 
- * @param g the object
- */
-void BPendingGroup_Init (BPendingGroup *g);
-
-/**
- * Frees the object.
- * There must be no {@link BPending} or {@link BSmallPending} objects using
- * this group.
- * 
- * @param g the object
- */
-void BPendingGroup_Free (BPendingGroup *g);
-
-/**
- * Checks if there is at least one job in the queue.
- * 
- * @param g the object
- * @return 1 if there is at least one job, 0 if not
- */
-int BPendingGroup_HasJobs (BPendingGroup *g);
-
-/**
- * Executes the top job on the job list.
- * The job is removed from the list and enters
- * not set state before being executed.
- * There must be at least one job in job list.
- * 
- * @param g the object
- */
-void BPendingGroup_ExecuteJob (BPendingGroup *g);
-
-/**
- * Returns the top job on the job list, or NULL if there are none.
- * 
- * @param g the object
- * @return the top job if there is at least one job, NULL if not
- */
-BSmallPending * BPendingGroup_PeekJob (BPendingGroup *g);
-
-/**
- * Initializes the object.
- * The object is initialized in not set state.
- * 
- * @param o the object
- * @param g pending group to use
- * @param handler job execution handler
- * @param user value to pass to handler
- */
-void BSmallPending_Init (BSmallPending *o, BPendingGroup *g, BSmallPending_handler handler, void *user);
-
-/**
- * Frees the object.
- * The execution handler will not be called after the object
- * is freed.
- * 
- * @param o the object
- * @param g pending group. Must be the same as was used in {@link BSmallPending_Init}.
- */
-void BSmallPending_Free (BSmallPending *o, BPendingGroup *g);
-
-/**
- * Changes the job execution handler.
- * 
- * @param o the object
- * @param handler job execution handler
- * @param user value to pass to handler
- */
-void BSmallPending_SetHandler (BSmallPending *o, BSmallPending_handler handler, void *user);
-
-/**
- * Enables the job, pushing it to the top of the job list.
- * If the object was already in set state, the job is removed from its
- * current position in the list before being pushed.
- * The object enters set state.
- * 
- * @param o the object
- * @param g pending group. Must be the same as was used in {@link BSmallPending_Init}.
- */
-void BSmallPending_Set (BSmallPending *o, BPendingGroup *g);
-
-/**
- * Disables the job, removing it from the job list.
- * If the object was not in set state, nothing is done.
- * The object enters not set state.
- * 
- * @param o the object
- * @param g pending group. Must be the same as was used in {@link BSmallPending_Init}.
- */
-void BSmallPending_Unset (BSmallPending *o, BPendingGroup *g);
-
-/**
- * Checks if the job is in set state.
- * 
- * @param o the object
- * @return 1 if in set state, 0 if not
- */
-int BSmallPending_IsSet (BSmallPending *o);
-
-/**
- * Initializes the object.
- * The object is initialized in not set state.
- * 
- * @param o the object
- * @param g pending group to use
- * @param handler job execution handler
- * @param user value to pass to handler
- */
-void BPending_Init (BPending *o, BPendingGroup *g, BPending_handler handler, void *user);
-
-/**
- * Frees the object.
- * The execution handler will not be called after the object
- * is freed.
- * 
- * @param o the object
- */
-void BPending_Free (BPending *o);
-
-/**
- * Enables the job, pushing it to the top of the job list.
- * If the object was already in set state, the job is removed from its
- * current position in the list before being pushed.
- * The object enters set state.
- * 
- * @param o the object
- */
-void BPending_Set (BPending *o);
-
-/**
- * Disables the job, removing it from the job list.
- * If the object was not in set state, nothing is done.
- * The object enters not set state.
- * 
- * @param o the object
- */
-void BPending_Unset (BPending *o);
-
-/**
- * Checks if the job is in set state.
- * 
- * @param o the object
- * @return 1 if in set state, 0 if not
- */
-int BPending_IsSet (BPending *o);
-
-#endif
diff --git a/external/badvpn_dns/base/BPending_list.h b/external/badvpn_dns/base/BPending_list.h
deleted file mode 100644
index eadac61..0000000
--- a/external/badvpn_dns/base/BPending_list.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#define SLINKEDLIST_PARAM_NAME BPending__List
-#define SLINKEDLIST_PARAM_FEATURE_LAST 0
-#define SLINKEDLIST_PARAM_TYPE_ENTRY struct BSmallPending_s
-#define SLINKEDLIST_PARAM_MEMBER_NODE pending_node
diff --git a/external/badvpn_dns/base/CMakeLists.txt b/external/badvpn_dns/base/CMakeLists.txt
deleted file mode 100644
index cf1f0f0..0000000
--- a/external/badvpn_dns/base/CMakeLists.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-set(BASE_ADDITIONAL_SOURCES)
-
-if (HAVE_SYSLOG_H)
-    list(APPEND BASE_ADDITIONAL_SOURCES BLog_syslog.c)
-endif ()
-
-set(BASE_SOURCES
-    DebugObject.c
-    BLog.c
-    BPending.c
-    ${BASE_ADDITIONAL_SOURCES}
-)
-badvpn_add_library(base "" "" "${BASE_SOURCES}")
diff --git a/external/badvpn_dns/base/DebugObject.c b/external/badvpn_dns/base/DebugObject.c
deleted file mode 100644
index e694617..0000000
--- a/external/badvpn_dns/base/DebugObject.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * @file DebugObject.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "DebugObject.h"
-
-#ifndef BADVPN_PLUGIN
-#ifndef NDEBUG
-DebugCounter debugobject_counter = DEBUGCOUNTER_STATIC;
-#if BADVPN_THREAD_SAFE
-pthread_mutex_t debugobject_mutex = PTHREAD_MUTEX_INITIALIZER;
-#endif
-#endif
-#endif
diff --git a/external/badvpn_dns/base/DebugObject.h b/external/badvpn_dns/base/DebugObject.h
deleted file mode 100644
index b8db287..0000000
--- a/external/badvpn_dns/base/DebugObject.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/**
- * @file DebugObject.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Object used for detecting leaks.
- */
-
-#ifndef BADVPN_DEBUGOBJECT_H
-#define BADVPN_DEBUGOBJECT_H
-
-#include <stdint.h>
-
-#if !defined(BADVPN_THREAD_SAFE) || (BADVPN_THREAD_SAFE != 0 && BADVPN_THREAD_SAFE != 1)
-#error BADVPN_THREAD_SAFE is not defined or incorrect
-#endif
-
-#if BADVPN_THREAD_SAFE
-#include <pthread.h>
-#endif
-
-#include <misc/debug.h>
-#include <misc/debugcounter.h>
-
-#define DEBUGOBJECT_VALID UINT32_C(0x31415926)
-
-/**
- * Object used for detecting leaks.
- */
-typedef struct {
-    #ifndef NDEBUG
-    uint32_t c;
-    #endif
-} DebugObject;
-
-/**
- * Initializes the object.
- * 
- * @param obj the object
- */
-static void DebugObject_Init (DebugObject *obj);
-
-/**
- * Frees the object.
- * 
- * @param obj the object
- */
-static void DebugObject_Free (DebugObject *obj);
-
-/**
- * Does nothing.
- * 
- * @param obj the object
- */
-static void DebugObject_Access (const DebugObject *obj);
-
-/**
- * Does nothing.
- * There must be no {@link DebugObject}'s initialized.
- */
-static void DebugObjectGlobal_Finish (void);
-
-#ifndef NDEBUG
-extern DebugCounter debugobject_counter;
-#if BADVPN_THREAD_SAFE
-extern pthread_mutex_t debugobject_mutex;
-#endif
-#endif
-
-void DebugObject_Init (DebugObject *obj)
-{
-    #ifndef NDEBUG
-    
-    obj->c = DEBUGOBJECT_VALID;
-    
-    #if BADVPN_THREAD_SAFE
-    ASSERT_FORCE(pthread_mutex_lock(&debugobject_mutex) == 0)
-    #endif
-    
-    DebugCounter_Increment(&debugobject_counter);
-    
-    #if BADVPN_THREAD_SAFE
-    ASSERT_FORCE(pthread_mutex_unlock(&debugobject_mutex) == 0)
-    #endif
-    
-    #endif
-}
-
-void DebugObject_Free (DebugObject *obj)
-{
-    ASSERT(obj->c == DEBUGOBJECT_VALID)
-    
-    #ifndef NDEBUG
-    
-    obj->c = 0;
-    
-    #if BADVPN_THREAD_SAFE
-    ASSERT_FORCE(pthread_mutex_lock(&debugobject_mutex) == 0)
-    #endif
-    
-    DebugCounter_Decrement(&debugobject_counter);
-    
-    #if BADVPN_THREAD_SAFE
-    ASSERT_FORCE(pthread_mutex_unlock(&debugobject_mutex) == 0)
-    #endif
-    
-    #endif
-}
-
-void DebugObject_Access (const DebugObject *obj)
-{
-    ASSERT(obj->c == DEBUGOBJECT_VALID)
-}
-
-void DebugObjectGlobal_Finish (void)
-{
-    #ifndef NDEBUG
-    DebugCounter_Free(&debugobject_counter);
-    #endif
-}
-
-#endif
diff --git a/external/badvpn_dns/blog_channels.txt b/external/badvpn_dns/blog_channels.txt
deleted file mode 100644
index 96313b5..0000000
--- a/external/badvpn_dns/blog_channels.txt
+++ /dev/null
@@ -1,145 +0,0 @@
-server 4
-client 4
-flooder 4
-tun2socks 4
-ncd 4
-ncd_var 4
-ncd_list 4
-ncd_depend 4
-ncd_multidepend 4
-ncd_dynamic_depend 4
-ncd_concat 4
-ncd_if 4
-ncd_strcmp 4
-ncd_regex_match 4
-ncd_logical 4
-ncd_sleep 4
-ncd_print 4
-ncd_blocker 4
-ncd_run 4
-ncd_runonce 4
-ncd_daemon 4
-ncd_spawn 4
-ncd_imperative 4
-ncd_ref 4
-ncd_index 4
-ncd_alias 4
-ncd_process_manager 4
-ncd_ondemand 4
-ncd_foreach 4
-ncd_choose 4
-ncd_net_backend_waitdevice 4
-ncd_net_backend_waitlink 4
-ncd_net_backend_badvpn 4
-ncd_net_backend_wpa_supplicant 4
-ncd_net_backend_rfkill 4
-ncd_net_up 4
-ncd_net_dns 4
-ncd_net_iptables 4
-ncd_net_ipv4_addr 4
-ncd_net_ipv4_route 4
-ncd_net_ipv4_dhcp 4
-ncd_net_ipv4_arp_probe 4
-ncd_net_watch_interfaces 4
-ncd_sys_watch_input 4
-ncd_sys_watch_usb 4
-ncd_sys_evdev 4
-ncd_sys_watch_directory 4
-StreamPeerIO 4
-DatagramPeerIO 4
-BReactor 3
-BSignal 3
-FragmentProtoAssembler 4
-BPredicate 3
-ServerConnection 4
-Listener 4
-DataProto 4
-FrameDecider 4
-BSocksClient 4
-BDHCPClientCore 4
-BDHCPClient 4
-NCDIfConfig 4
-BUnixSignal 4
-BProcess 4
-PRStreamSink 4
-PRStreamSource 4
-PacketProtoDecoder 4
-DPRelay 4
-BThreadWork 4
-DPReceive 4
-BInputProcess 4
-NCDUdevMonitorParser 4
-NCDUdevMonitor 4
-NCDUdevCache 4
-NCDUdevManager 4
-BTime 4
-BEncryption 4
-SPProtoDecoder 4
-LineBuffer 4
-BTap 4
-lwip 4
-NCDConfigTokenizer 4
-NCDConfigParser 4
-NCDValParser 4
-nsskey 4
-addr 4
-PasswordListener 4
-NCDInterfaceMonitor 4
-NCDRfkillMonitor 4
-udpgw 4
-UdpGwClient 4
-SocksUdpGwClient 4
-BNetwork 4
-BConnection 4
-BSSLConnection 4
-BDatagram 4
-PeerChat 4
-BArpProbe 4
-NCDModuleIndex 4
-NCDModuleProcess 4
-NCDValGenerator 4
-ncd_from_string 4
-ncd_to_string 4
-ncd_value 4
-ncd_try 4
-ncd_sys_request_server 4
-NCDRequest 4
-ncd_net_ipv6_wait_dynamic_addr 4
-NCDRequestClient 4
-ncd_request 4
-ncd_sys_request_client 4
-ncd_exit 4
-ncd_getargs 4
-ncd_arithmetic 4
-ncd_parse 4
-ncd_valuemetic 4
-ncd_file 4
-ncd_netmask 4
-ncd_implode 4
-ncd_call2 4
-ncd_assert 4
-ncd_reboot 4
-ncd_explode 4
-NCDPlaceholderDb 4
-NCDVal 4
-ncd_net_ipv6_addr 4
-ncd_net_ipv6_route 4
-ncd_net_ipv4_addr_in_network 4
-ncd_net_ipv6_addr_in_network 4
-dostest_server 4
-dostest_attacker 4
-ncd_timer 4
-ncd_file_open 4
-ncd_backtrack 4
-ncd_socket 4
-ncd_depend_scope 4
-ncd_substr 4
-ncd_sys_start_process 4
-NCDBuildProgram 4
-ncd_log 4
-ncd_log_msg 4
-ncd_buffer 4
-ncd_getenv 4
-BThreadSignal 4
-BLockReactor 4
-ncd_load_module 4
diff --git a/external/badvpn_dns/blog_generator/blog.php b/external/badvpn_dns/blog_generator/blog.php
deleted file mode 100644
index fd436bc..0000000
--- a/external/badvpn_dns/blog_generator/blog.php
+++ /dev/null
@@ -1,121 +0,0 @@
-<?php
-
-require_once "blog_functions.php";
-
-function assert_failure ($script, $line, $message)
-{
-    if ($message == "") {
-        fatal_error("Assertion failure at {$script}:{$line}");
-    } else {
-        fatal_error("Assertion failure at {$script}:{$line}: {$message}");
-    }
-}
-
-assert_options(ASSERT_CALLBACK, "assert_failure");
-
-function print_help ($name)
-{
-    echo <<<EOD
-Usage: {$name}
-    --input-file <file>         Input channels file.
-    --output-dir <dir>          Destination directory for generated files.
-
-EOD;
-}
-
-$input_file = "";
-$output_dir = "";
-
-for ($i = 1; $i < $argc;) {
-    $arg = $argv[$i++];
-    switch ($arg) {
-        case "--input-file":
-            $input_file = $argv[$i++];
-            break;
-        case "--output-dir":
-            $output_dir = $argv[$i++];
-            break;
-        case "--help":
-            print_help($argv[0]);
-            exit(0);
-        default:
-            fatal_error("Unknown option: {$arg}");
-    }
-}
-
-if ($input_file == "") {
-    fatal_error("--input-file missing");
-}
-
-if ($output_dir == "") {
-    fatal_error("--output-dir missing");
-}
-
-if (($data = file_get_contents($input_file)) === FALSE) {
-    fatal_error("Failed to read input file");
-}
-
-if (!tokenize($data, $tokens)) {
-    fatal_error("Failed to tokenize");
-}
-
-$i = 0;
-$channels_defines = "";
-$channels_list = "";
-
-reset($tokens);
-
-while (1) {
-    if (($ch_name = current($tokens)) === FALSE) {
-        break;
-    }
-    next($tokens);
-    if (($ch_priority = current($tokens)) === FALSE) {
-        fatal_error("missing priority");
-    }
-    next($tokens);
-    if ($ch_name[0] != "name") {
-        fatal_error("name is not a name");
-    }
-    if ($ch_priority[0] != "number") {
-        fatal_error("priority is not a number");
-    }
-
-    $channel_file = <<<EOD
-#ifdef BLOG_CURRENT_CHANNEL
-#undef BLOG_CURRENT_CHANNEL
-#endif
-#define BLOG_CURRENT_CHANNEL BLOG_CHANNEL_{$ch_name[1]}
-
-EOD;
-
-    $channels_defines .= <<<EOD
-#define BLOG_CHANNEL_{$ch_name[1]} {$i}
-
-EOD;
-
-    $channels_list .= <<<EOD
-{"{$ch_name[1]}", {$ch_priority[1]}},
-
-EOD;
-
-    if (file_put_contents("{$output_dir}/blog_channel_{$ch_name[1]}.h", $channel_file) === NULL) {
-        fatal_error("{$input_file}: Failed to write channel file");
-    }
-
-    $i++;
-}
-
-$channels_defines .= <<<EOD
-#define BLOG_NUM_CHANNELS {$i}
-
-EOD;
-
-if (file_put_contents("{$output_dir}/blog_channels_defines.h", $channels_defines) === NULL) {
-    fatal_error("{$input_file}: Failed to write channels defines file");
-}
-
-if (file_put_contents("{$output_dir}/blog_channels_list.h", $channels_list) === NULL) {
-    fatal_error("{$input_file}: Failed to write channels list file");
-}
-
diff --git a/external/badvpn_dns/blog_generator/blog_functions.php b/external/badvpn_dns/blog_generator/blog_functions.php
deleted file mode 100644
index ba4be89..0000000
--- a/external/badvpn_dns/blog_generator/blog_functions.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-
-function tokenize ($str, &$out) {
-    $out = array();
-
-    while (strlen($str) > 0) {
-        if (preg_match('/^\\/\\/.*/', $str, $matches)) {
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^\\s+/', $str, $matches)) {
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^[0-9]+/', $str, $matches)) {
-            $out[] = array('number', $matches[0]);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*/', $str, $matches)) {
-            $out[] = array('name', $matches[0]);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else {
-            return FALSE;
-        }
-    }
-
-    return TRUE;
-}
-
-function fatal_error ($message)
-{
-    fwrite(STDERR, "Fatal error: $message\n");
-
-    ob_get_clean();
-    exit(1);
-}
diff --git a/external/badvpn_dns/bproto/BProto.h b/external/badvpn_dns/bproto/BProto.h
deleted file mode 100644
index 5f2a696..0000000
--- a/external/badvpn_dns/bproto/BProto.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * @file BProto.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Definitions for BProto serialization.
- */
-
-#ifndef BADVPN_BPROTO_BPROTO_H
-#define BADVPN_BPROTO_BPROTO_H
-
-#include <stdint.h>
-
-#include <misc/packed.h>
-
-#define BPROTO_TYPE_UINT8 1
-#define BPROTO_TYPE_UINT16 2
-#define BPROTO_TYPE_UINT32 3
-#define BPROTO_TYPE_UINT64 4
-#define BPROTO_TYPE_DATA 5
-#define BPROTO_TYPE_CONSTDATA 6
-
-B_START_PACKED
-struct BProto_header_s {
-    uint16_t id;
-    uint16_t type;
-} B_PACKED;
-B_END_PACKED
-
-B_START_PACKED
-struct BProto_uint8_s {
-    uint8_t v;
-} B_PACKED;
-B_END_PACKED
-
-B_START_PACKED
-struct BProto_uint16_s {
-    uint16_t v;
-} B_PACKED;
-B_END_PACKED
-
-B_START_PACKED
-struct BProto_uint32_s {
-    uint32_t v;
-} B_PACKED;
-B_END_PACKED
-
-B_START_PACKED
-struct BProto_uint64_s {
-    uint64_t v;
-} B_PACKED;
-B_END_PACKED
-
-B_START_PACKED
-struct BProto_data_header_s {
-    uint32_t len;
-} B_PACKED;
-B_END_PACKED
-
-#endif
diff --git a/external/badvpn_dns/bproto_generator/ProtoParser.lime b/external/badvpn_dns/bproto_generator/ProtoParser.lime
deleted file mode 100644
index f039e1d..0000000
--- a/external/badvpn_dns/bproto_generator/ProtoParser.lime
+++ /dev/null
@@ -1,99 +0,0 @@
-%class ProtoParser
-%start file
-
-file =
-    directives messages {
-        $$ = array(
-            "directives" => $1,
-            "messages" => $2
-        );
-    }.
-
-directives =
-    {
-        $$ = array();
-    } |
-    directive semicolon directives {
-        $$ = array_merge(array($1), $3);
-    }.
-
-directive =
-    include string {
-        $$ = array(
-            "type" => "include",
-            "file" => $2
-        );
-    }.
-
-messages =
-    msgspec {
-        $$ = array($1);
-    } |
-    msgspec messages {
-        $$ = array_merge(array($1), $2);
-    }.
-
-msgspec =
-    message name spar entries epar semicolon {
-    $$ = array(
-        "name" => $2,
-        "entries" => $4
-    );
-}.
-
-entries =
-    entry {
-        $$ = array($1);
-    } |
-    entry entries {
-        $$ = array_merge(array($1), $2);
-    }.
-
-entry =
-    cardinality type name equals number semicolon {
-        $$ = array(
-            "cardinality" => $1,
-            "type" => $2,
-            "name" => $3,
-            "id" => $5
-        );
-    }.
-
-cardinality =
-    repeated {
-        $$ = "repeated";
-    } |
-    optional {
-        $$ = "optional";
-    } |
-    required {
-        $$ = "required";
-    } |
-    required repeated {
-        $$ = "required repeated";
-    }.
-
-type =
-    uint {
-        $$ = array(
-            "type" => "uint",
-            "size" => $1
-        );
-    } |
-    data {
-        $$ = array(
-            "type" => "data"
-        );
-    } |
-    data srpar string erpar {
-        $$ = array(
-            "type" => "constdata",
-            "size" => $3
-        );
-    } |
-    message name {
-        $$ = array(
-            "type" => "message",
-            "message" => $2
-        );
-    }.
diff --git a/external/badvpn_dns/bproto_generator/ProtoParser.php b/external/badvpn_dns/bproto_generator/ProtoParser.php
deleted file mode 100644
index 0477dba..0000000
--- a/external/badvpn_dns/bproto_generator/ProtoParser.php
+++ /dev/null
@@ -1,560 +0,0 @@
-<?php
-
-
-/*
-
-DON'T EDIT THIS FILE!
-
-This file was automatically generated by the Lime parser generator.
-The real source code you should be looking at is in one or more
-grammar files in the Lime format.
-
-THE ONLY REASON TO LOOK AT THIS FILE is to see where in the grammar
-file that your error happened, because there are enough comments to
-help you debug your grammar.
-
-If you ignore this warning, you're shooting yourself in the brain,
-not the foot.
-
-*/
-
-class ProtoParser extends lime_parser {
-var $qi = 0;
-var $i = array (
-  0 => 
-  array (
-    'directives' => 's 1',
-    'directive' => 's 30',
-    'include' => 's 33',
-    'file' => 's 35',
-    '\'start\'' => 'a \'start\'',
-    'message' => 'r 1',
-  ),
-  1 => 
-  array (
-    'messages' => 's 2',
-    'msgspec' => 's 3',
-    'message' => 's 5',
-  ),
-  2 => 
-  array (
-    '#' => 'r 0',
-  ),
-  3 => 
-  array (
-    'msgspec' => 's 3',
-    'messages' => 's 4',
-    'message' => 's 5',
-    '#' => 'r 4',
-  ),
-  4 => 
-  array (
-    '#' => 'r 5',
-  ),
-  5 => 
-  array (
-    'name' => 's 6',
-  ),
-  6 => 
-  array (
-    'spar' => 's 7',
-  ),
-  7 => 
-  array (
-    'entries' => 's 8',
-    'entry' => 's 11',
-    'cardinality' => 's 13',
-    'repeated' => 's 26',
-    'optional' => 's 27',
-    'required' => 's 28',
-  ),
-  8 => 
-  array (
-    'epar' => 's 9',
-  ),
-  9 => 
-  array (
-    'semicolon' => 's 10',
-  ),
-  10 => 
-  array (
-    'message' => 'r 6',
-    '#' => 'r 6',
-  ),
-  11 => 
-  array (
-    'entry' => 's 11',
-    'entries' => 's 12',
-    'cardinality' => 's 13',
-    'repeated' => 's 26',
-    'optional' => 's 27',
-    'required' => 's 28',
-    'epar' => 'r 7',
-  ),
-  12 => 
-  array (
-    'epar' => 'r 8',
-  ),
-  13 => 
-  array (
-    'type' => 's 14',
-    'uint' => 's 19',
-    'data' => 's 20',
-    'message' => 's 24',
-  ),
-  14 => 
-  array (
-    'name' => 's 15',
-  ),
-  15 => 
-  array (
-    'equals' => 's 16',
-  ),
-  16 => 
-  array (
-    'number' => 's 17',
-  ),
-  17 => 
-  array (
-    'semicolon' => 's 18',
-  ),
-  18 => 
-  array (
-    'repeated' => 'r 9',
-    'optional' => 'r 9',
-    'required' => 'r 9',
-    'epar' => 'r 9',
-  ),
-  19 => 
-  array (
-    'name' => 'r 14',
-  ),
-  20 => 
-  array (
-    'srpar' => 's 21',
-    'name' => 'r 15',
-  ),
-  21 => 
-  array (
-    'string' => 's 22',
-  ),
-  22 => 
-  array (
-    'erpar' => 's 23',
-  ),
-  23 => 
-  array (
-    'name' => 'r 16',
-  ),
-  24 => 
-  array (
-    'name' => 's 25',
-  ),
-  25 => 
-  array (
-    'name' => 'r 17',
-  ),
-  26 => 
-  array (
-    'uint' => 'r 10',
-    'data' => 'r 10',
-    'message' => 'r 10',
-  ),
-  27 => 
-  array (
-    'uint' => 'r 11',
-    'data' => 'r 11',
-    'message' => 'r 11',
-  ),
-  28 => 
-  array (
-    'repeated' => 's 29',
-    'uint' => 'r 12',
-    'data' => 'r 12',
-    'message' => 'r 12',
-  ),
-  29 => 
-  array (
-    'uint' => 'r 13',
-    'data' => 'r 13',
-    'message' => 'r 13',
-  ),
-  30 => 
-  array (
-    'semicolon' => 's 31',
-  ),
-  31 => 
-  array (
-    'directive' => 's 30',
-    'directives' => 's 32',
-    'include' => 's 33',
-    'message' => 'r 1',
-  ),
-  32 => 
-  array (
-    'message' => 'r 2',
-  ),
-  33 => 
-  array (
-    'string' => 's 34',
-  ),
-  34 => 
-  array (
-    'semicolon' => 'r 3',
-  ),
-  35 => 
-  array (
-    '#' => 'r 18',
-  ),
-);
-function reduce_0_file_1($tokens, &$result) {
-#
-# (0) file :=  directives  messages
-#
-$result = reset($tokens);
-
-    $result = array(
-        "directives" => $tokens[0],
-        "messages" => $tokens[1]
-    );
-
-}
-
-function reduce_1_directives_1($tokens, &$result) {
-#
-# (1) directives :=
-#
-$result = reset($tokens);
-
-        $result = array();
-    
-}
-
-function reduce_2_directives_2($tokens, &$result) {
-#
-# (2) directives :=  directive  semicolon  directives
-#
-$result = reset($tokens);
-
-        $result = array_merge(array($tokens[0]), $tokens[2]);
-    
-}
-
-function reduce_3_directive_1($tokens, &$result) {
-#
-# (3) directive :=  include  string
-#
-$result = reset($tokens);
-
-        $result = array(
-            "type" => "include",
-            "file" => $tokens[1]
-        );
-    
-}
-
-function reduce_4_messages_1($tokens, &$result) {
-#
-# (4) messages :=  msgspec
-#
-$result = reset($tokens);
-
-        $result = array($tokens[0]);
-    
-}
-
-function reduce_5_messages_2($tokens, &$result) {
-#
-# (5) messages :=  msgspec  messages
-#
-$result = reset($tokens);
-
-        $result = array_merge(array($tokens[0]), $tokens[1]);
-    
-}
-
-function reduce_6_msgspec_1($tokens, &$result) {
-#
-# (6) msgspec :=  message  name  spar  entries  epar  semicolon
-#
-$result = reset($tokens);
-
-    $result = array(
-        "name" => $tokens[1],
-        "entries" => $tokens[3]
-    );
-
-}
-
-function reduce_7_entries_1($tokens, &$result) {
-#
-# (7) entries :=  entry
-#
-$result = reset($tokens);
-
-        $result = array($tokens[0]);
-    
-}
-
-function reduce_8_entries_2($tokens, &$result) {
-#
-# (8) entries :=  entry  entries
-#
-$result = reset($tokens);
-
-        $result = array_merge(array($tokens[0]), $tokens[1]);
-    
-}
-
-function reduce_9_entry_1($tokens, &$result) {
-#
-# (9) entry :=  cardinality  type  name  equals  number  semicolon
-#
-$result = reset($tokens);
-
-        $result = array(
-            "cardinality" => $tokens[0],
-            "type" => $tokens[1],
-            "name" => $tokens[2],
-            "id" => $tokens[4]
-        );
-    
-}
-
-function reduce_10_cardinality_1($tokens, &$result) {
-#
-# (10) cardinality :=  repeated
-#
-$result = reset($tokens);
-
-        $result = "repeated";
-    
-}
-
-function reduce_11_cardinality_2($tokens, &$result) {
-#
-# (11) cardinality :=  optional
-#
-$result = reset($tokens);
-
-        $result = "optional";
-    
-}
-
-function reduce_12_cardinality_3($tokens, &$result) {
-#
-# (12) cardinality :=  required
-#
-$result = reset($tokens);
-
-        $result = "required";
-    
-}
-
-function reduce_13_cardinality_4($tokens, &$result) {
-#
-# (13) cardinality :=  required  repeated
-#
-$result = reset($tokens);
-
-        $result = "required repeated";
-    
-}
-
-function reduce_14_type_1($tokens, &$result) {
-#
-# (14) type :=  uint
-#
-$result = reset($tokens);
-
-        $result = array(
-            "type" => "uint",
-            "size" => $tokens[0]
-        );
-    
-}
-
-function reduce_15_type_2($tokens, &$result) {
-#
-# (15) type :=  data
-#
-$result = reset($tokens);
-
-        $result = array(
-            "type" => "data"
-        );
-    
-}
-
-function reduce_16_type_3($tokens, &$result) {
-#
-# (16) type :=  data  srpar  string  erpar
-#
-$result = reset($tokens);
-
-        $result = array(
-            "type" => "constdata",
-            "size" => $tokens[2]
-        );
-    
-}
-
-function reduce_17_type_4($tokens, &$result) {
-#
-# (17) type :=  message  name
-#
-$result = reset($tokens);
-
-        $result = array(
-            "type" => "message",
-            "message" => $tokens[1]
-        );
-    
-}
-
-function reduce_18_start_1($tokens, &$result) {
-#
-# (18) 'start' :=  file
-#
-$result = reset($tokens);
-
-}
-
-var $method = array (
-  0 => 'reduce_0_file_1',
-  1 => 'reduce_1_directives_1',
-  2 => 'reduce_2_directives_2',
-  3 => 'reduce_3_directive_1',
-  4 => 'reduce_4_messages_1',
-  5 => 'reduce_5_messages_2',
-  6 => 'reduce_6_msgspec_1',
-  7 => 'reduce_7_entries_1',
-  8 => 'reduce_8_entries_2',
-  9 => 'reduce_9_entry_1',
-  10 => 'reduce_10_cardinality_1',
-  11 => 'reduce_11_cardinality_2',
-  12 => 'reduce_12_cardinality_3',
-  13 => 'reduce_13_cardinality_4',
-  14 => 'reduce_14_type_1',
-  15 => 'reduce_15_type_2',
-  16 => 'reduce_16_type_3',
-  17 => 'reduce_17_type_4',
-  18 => 'reduce_18_start_1',
-);
-var $a = array (
-  0 => 
-  array (
-    'symbol' => 'file',
-    'len' => 2,
-    'replace' => true,
-  ),
-  1 => 
-  array (
-    'symbol' => 'directives',
-    'len' => 0,
-    'replace' => true,
-  ),
-  2 => 
-  array (
-    'symbol' => 'directives',
-    'len' => 3,
-    'replace' => true,
-  ),
-  3 => 
-  array (
-    'symbol' => 'directive',
-    'len' => 2,
-    'replace' => true,
-  ),
-  4 => 
-  array (
-    'symbol' => 'messages',
-    'len' => 1,
-    'replace' => true,
-  ),
-  5 => 
-  array (
-    'symbol' => 'messages',
-    'len' => 2,
-    'replace' => true,
-  ),
-  6 => 
-  array (
-    'symbol' => 'msgspec',
-    'len' => 6,
-    'replace' => true,
-  ),
-  7 => 
-  array (
-    'symbol' => 'entries',
-    'len' => 1,
-    'replace' => true,
-  ),
-  8 => 
-  array (
-    'symbol' => 'entries',
-    'len' => 2,
-    'replace' => true,
-  ),
-  9 => 
-  array (
-    'symbol' => 'entry',
-    'len' => 6,
-    'replace' => true,
-  ),
-  10 => 
-  array (
-    'symbol' => 'cardinality',
-    'len' => 1,
-    'replace' => true,
-  ),
-  11 => 
-  array (
-    'symbol' => 'cardinality',
-    'len' => 1,
-    'replace' => true,
-  ),
-  12 => 
-  array (
-    'symbol' => 'cardinality',
-    'len' => 1,
-    'replace' => true,
-  ),
-  13 => 
-  array (
-    'symbol' => 'cardinality',
-    'len' => 2,
-    'replace' => true,
-  ),
-  14 => 
-  array (
-    'symbol' => 'type',
-    'len' => 1,
-    'replace' => true,
-  ),
-  15 => 
-  array (
-    'symbol' => 'type',
-    'len' => 1,
-    'replace' => true,
-  ),
-  16 => 
-  array (
-    'symbol' => 'type',
-    'len' => 4,
-    'replace' => true,
-  ),
-  17 => 
-  array (
-    'symbol' => 'type',
-    'len' => 2,
-    'replace' => true,
-  ),
-  18 => 
-  array (
-    'symbol' => '\'start\'',
-    'len' => 1,
-    'replace' => true,
-  ),
-);
-}
diff --git a/external/badvpn_dns/bproto_generator/bproto.php b/external/badvpn_dns/bproto_generator/bproto.php
deleted file mode 100644
index 76f8c6e..0000000
--- a/external/badvpn_dns/bproto_generator/bproto.php
+++ /dev/null
@@ -1,115 +0,0 @@
-<?php
-/**
- * @file bproto.php
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-require_once "lime/parse_engine.php";
-require_once "ProtoParser.php";
-require_once "bproto_functions.php";
-
-function assert_failure ($script, $line, $message)
-{
-    if ($message == "") {
-        fatal_error("Assertion failure at {$script}:{$line}");
-    } else {
-        fatal_error("Assertion failure at {$script}:{$line}: {$message}");
-    }
-}
-
-assert_options(ASSERT_CALLBACK, "assert_failure");
-
-function print_help ($name)
-{
-    echo <<<EOD
-Usage: {$name}
-    --name <string>             Output file prefix.
-    --input-file <file>         Message file to generate source for.
-    --output-dir <dir>          Destination directory for generated files.
-
-EOD;
-}
-
-$name = "";
-$input_file = "";
-$output_dir = "";
-
-for ($i = 1; $i < $argc;) {
-    $arg = $argv[$i++];
-    switch ($arg) {
-        case "--name":
-            $name = $argv[$i++];
-            break;
-        case "--input-file":
-            $input_file = $argv[$i++];
-            break;
-        case "--output-dir":
-            $output_dir = $argv[$i++];
-            break;
-        case "--help":
-            print_help($argv[0]);
-            exit(0);
-        default:
-            fatal_error("Unknown option: {$arg}");
-    }
-}
-
-if ($name == "") {
-    fatal_error("--name missing");
-}
-
-if ($input_file == "") {
-    fatal_error("--input-file missing");
-}
-
-if ($output_dir == "") {
-    fatal_error("--output-dir missing");
-}
-
-if (($data = file_get_contents($input_file)) === FALSE) {
-    fatal_error("Failed to read input file");
-}
-
-if (!tokenize($data, $tokens)) {
-    fatal_error("Failed to tokenize");
-}
-
-$parser = new parse_engine(new ProtoParser());
-
-try {
-    foreach ($tokens as $token) {
-        $parser->eat($token[0], $token[1]);
-    }
-    $parser->eat_eof();
-} catch (parse_error $e) {
-    fatal_error("$input_file: Parse error: ".$e->getMessage());
-}
-
-$data = generate_header($name, $parser->semantic["directives"], $parser->semantic["messages"]);
-if (file_put_contents("{$output_dir}/{$name}.h", $data) === NULL) {
-    fatal_error("{$input_file}: Failed to write .h file");
-}
diff --git a/external/badvpn_dns/bproto_generator/bproto_functions.php b/external/badvpn_dns/bproto_generator/bproto_functions.php
deleted file mode 100644
index 490c1bf..0000000
--- a/external/badvpn_dns/bproto_generator/bproto_functions.php
+++ /dev/null
@@ -1,777 +0,0 @@
-<?php
-
-function tokenize ($str, &$out) {
-    $out = array();
-
-    while (strlen($str) > 0) {
-        if (preg_match('/^\\/\\/.*/', $str, $matches)) {
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^\\s+/', $str, $matches)) {
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^include/', $str, $matches)) {
-            $out[] = array('include', null);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^message/', $str, $matches)) {
-            $out[] = array('message', null);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^repeated/', $str, $matches)) {
-            $out[] = array('repeated', null);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^required/', $str, $matches)) {
-            $out[] = array('required', null);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^optional/', $str, $matches)) {
-            $out[] = array('optional', null);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^{/', $str, $matches)) {
-            $out[] = array('spar', null);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^}/', $str, $matches)) {
-            $out[] = array('epar', null);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^\(/', $str, $matches)) {
-            $out[] = array('srpar', null);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^\)/', $str, $matches)) {
-            $out[] = array('erpar', null);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^=/', $str, $matches)) {
-            $out[] = array('equals', null);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^;/', $str, $matches)) {
-            $out[] = array('semicolon', null);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^uint(8|16|32|64)/', $str, $matches)) {
-            $out[] = array('uint', $matches[1]);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^data/', $str, $matches)) {
-            $out[] = array('data', null);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^[0-9]+/', $str, $matches)) {
-            $out[] = array('number', $matches[0]);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*/', $str, $matches)) {
-            $out[] = array('name', $matches[0]);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else if (preg_match('/^"([^"]*)"/', $str, $matches)) {
-            $out[] = array('string', $matches[1]);
-            $str = substr($str, strlen($matches[0]));
-        }
-        else {
-            return FALSE;
-        }
-    }
-
-    return TRUE;
-}
-
-function fatal_error ($message)
-{
-    fwrite(STDERR, "Fatal error: $message\n");
-
-    ob_get_clean();
-    exit(1);
-}
-
-function make_writer_decl ($msg, $entry)
-{
-    switch ($entry["type"]["type"]) {
-        case "uint":
-            return "void {$msg["name"]}Writer_Add{$entry["name"]} ({$msg["name"]}Writer *o, uint{$entry["type"]["size"]}_t v)";
-        case "data":
-            return "uint8_t * {$msg["name"]}Writer_Add{$entry["name"]} ({$msg["name"]}Writer *o, int len)";
-        case "constdata":
-            return "uint8_t * {$msg["name"]}Writer_Add{$entry["name"]} ({$msg["name"]}Writer *o)";
-        default:
-            assert(0);
-    }
-}
-
-function make_parser_decl ($msg, $entry)
-{
-    switch ($entry["type"]["type"]) {
-        case "uint":
-            return "int {$msg["name"]}Parser_Get{$entry["name"]} ({$msg["name"]}Parser *o, uint{$entry["type"]["size"]}_t *v)";
-        case "data":
-            return "int {$msg["name"]}Parser_Get{$entry["name"]} ({$msg["name"]}Parser *o, uint8_t **data, int *data_len)";
-        case "constdata":
-            return "int {$msg["name"]}Parser_Get{$entry["name"]} ({$msg["name"]}Parser *o, uint8_t **data)";
-        default:
-            assert(0);
-    }
-}
-
-function make_parser_reset_decl ($msg, $entry)
-{
-    return "void {$msg["name"]}Parser_Reset{$entry["name"]} ({$msg["name"]}Parser *o)";
-}
-
-function make_parser_forward_decl ($msg, $entry)
-{
-    return "void {$msg["name"]}Parser_Forward{$entry["name"]} ({$msg["name"]}Parser *o)";
-}
-
-function make_type_name ($msg, $entry)
-{
-    switch ($entry["type"]["type"]) {
-        case "uint":
-            return "BPROTO_TYPE_UINT{$entry["type"]["size"]}";
-        case "data":
-            return "BPROTO_TYPE_DATA";
-        case "constdata":
-            return "BPROTO_TYPE_CONSTDATA";
-        default:
-            assert(0);
-    }
-}
-
-function make_finish_assert ($msg, $entry)
-{
-    switch ($entry["cardinality"]) {
-        case "repeated":
-            return "ASSERT(o->{$entry["name"]}_count >= 0)";
-        case "required repeated":
-            return "ASSERT(o->{$entry["name"]}_count >= 1)";
-        case "optional":
-            return "ASSERT(o->{$entry["name"]}_count >= 0 && o->{$entry["name"]}_count <= 1)";
-        case "required":
-            return "ASSERT(o->{$entry["name"]}_count == 1)";
-        default:
-            assert(0);
-    }
-}
-
-function make_add_count_assert ($msg, $entry)
-{
-    if (in_array($entry["cardinality"], array("optional", "required"))) {
-        return "ASSERT(o->{$entry["name"]}_count == 0)";
-    }
-    return "";
-}
-
-function make_add_length_assert ($msg, $entry)
-{
-    if ($entry["type"]["type"] == "data") {
-        return "ASSERT(len >= 0 && len <= UINT32_MAX)";
-    }
-    return "";
-}
-
-function make_size_define ($msg, $entry)
-{
-    switch ($entry["type"]["type"]) {
-        case "uint":
-            return "#define {$msg["name"]}_SIZE{$entry["name"]} (sizeof(struct BProto_header_s) + sizeof(struct BProto_uint{$entry["type"]["size"]}_s))";
-        case "data":
-            return "#define {$msg["name"]}_SIZE{$entry["name"]}(_len) (sizeof(struct BProto_header_s) + sizeof(struct BProto_data_header_s) + (_len))";
-        case "constdata":
-            return "#define {$msg["name"]}_SIZE{$entry["name"]} (sizeof(struct BProto_header_s) + sizeof(struct BProto_data_header_s) + ({$entry["type"]["size"]}))";
-        default:
-            assert(0);
-    }
-}
-
-function generate_header ($name, $directives, $messages) {
-    ob_start();
-
-    echo <<<EOD
-/*
-    DO NOT EDIT THIS FILE!
-    This file was automatically generated by the bproto generator.
-*/
-
-#include <stdint.h>
-#include <string.h>
-
-#include <misc/debug.h>
-#include <misc/byteorder.h>
-#include <bproto/BProto.h>
-
-
-EOD;
-
-    foreach ($directives as $directive) {
-        if ($directive["type"] == "include") {
-            echo <<<EOD
-#include "{$directive["file"]}"
-
-EOD;
-        }
-    }
-
-    echo <<<EOD
-
-
-EOD;
-
-    foreach ($messages as $msg) {
-
-        foreach ($msg["entries"] as $entry) {
-            $def = make_size_define($msg, $entry);
-            echo <<<EOD
-{$def}
-
-EOD;
-        }
-
-        echo <<<EOD
-
-typedef struct {
-    uint8_t *out;
-    int used;
-
-EOD;
-
-        foreach ($msg["entries"] as $entry) {
-            echo <<<EOD
-    int {$entry["name"]}_count;
-
-EOD;
-        }
-
-        echo <<<EOD
-} {$msg["name"]}Writer;
-
-static void {$msg["name"]}Writer_Init ({$msg["name"]}Writer *o, uint8_t *out);
-static int {$msg["name"]}Writer_Finish ({$msg["name"]}Writer *o);
-
-EOD;
-
-        foreach ($msg["entries"] as $entry) {
-            $decl = make_writer_decl($msg, $entry);
-            echo <<<EOD
-static {$decl};
-
-EOD;
-        }
-
-        echo <<<EOD
-
-typedef struct {
-    uint8_t *buf;
-    int buf_len;
-
-EOD;
-        foreach ($msg["entries"] as $entry) {
-            echo <<<EOD
-    int {$entry["name"]}_start;
-    int {$entry["name"]}_span;
-    int {$entry["name"]}_pos;
-
-EOD;
-        }
-
-        echo <<<EOD
-} {$msg["name"]}Parser;
-
-static int {$msg["name"]}Parser_Init ({$msg["name"]}Parser *o, uint8_t *buf, int buf_len);
-static int {$msg["name"]}Parser_GotEverything ({$msg["name"]}Parser *o);
-
-EOD;
-
-        foreach ($msg["entries"] as $entry) {
-            $decl = make_parser_decl($msg, $entry);
-            $reset_decl = make_parser_reset_decl($msg, $entry);
-            $forward_decl = make_parser_forward_decl($msg, $entry);
-            echo <<<EOD
-static {$decl};
-static {$reset_decl};
-static {$forward_decl};
-
-EOD;
-        }
-
-        echo <<<EOD
-
-void {$msg["name"]}Writer_Init ({$msg["name"]}Writer *o, uint8_t *out)
-{
-    o->out = out;
-    o->used = 0;
-
-EOD;
-
-        foreach ($msg["entries"] as $entry) {
-            echo <<<EOD
-    o->{$entry["name"]}_count = 0;
-
-EOD;
-        }
-
-        echo <<<EOD
-}
-
-int {$msg["name"]}Writer_Finish ({$msg["name"]}Writer *o)
-{
-    ASSERT(o->used >= 0)
-
-EOD;
-
-        foreach ($msg["entries"] as $entry) {
-            $ass = make_finish_assert($msg, $entry);
-            echo <<<EOD
-    {$ass}
-
-EOD;
-        }
-
-        echo <<<EOD
-
-    return o->used;
-}
-
-
-EOD;
-
-        foreach ($msg["entries"] as $entry) {
-            $decl = make_writer_decl($msg, $entry);
-            $type = make_type_name($msg, $entry);
-            $add_count_assert = make_add_count_assert($msg, $entry);
-            $add_length_assert = make_add_length_assert($msg, $entry);
-
-            echo <<<EOD
-{$decl}
-{
-    ASSERT(o->used >= 0)
-    {$add_count_assert}
-    {$add_length_assert}
-
-    struct BProto_header_s header;
-    header.id = htol16({$entry["id"]});
-    header.type = htol16({$type});
-    memcpy(o->out + o->used, &header, sizeof(header));
-    o->used += sizeof(struct BProto_header_s);
-
-
-EOD;
-            switch ($entry["type"]["type"]) {
-                case "uint":
-                    echo <<<EOD
-    struct BProto_uint{$entry["type"]["size"]}_s data;
-    data.v = htol{$entry["type"]["size"]}(v);
-    memcpy(o->out + o->used, &data, sizeof(data));
-    o->used += sizeof(struct BProto_uint{$entry["type"]["size"]}_s);
-
-EOD;
-                    break;
-                case "data":
-                    echo <<<EOD
-    struct BProto_data_header_s data;
-    data.len = htol32(len);
-    memcpy(o->out + o->used, &data, sizeof(data));
-    o->used += sizeof(struct BProto_data_header_s);
-
-    uint8_t *dest = (o->out + o->used);
-    o->used += len;
-
-EOD;
-                    break;
-                case "constdata":
-                    echo <<<EOD
-    struct BProto_data_header_s data;
-    data.len = htol32({$entry["type"]["size"]});
-    memcpy(o->out + o->used, &data, sizeof(data));
-    o->used += sizeof(struct BProto_data_header_s);
-
-    uint8_t *dest = (o->out + o->used);
-    o->used += ({$entry["type"]["size"]});
-
-EOD;
-                    break;
-                default:
-                    assert(0);
-            }
-
-            echo <<<EOD
-
-    o->{$entry["name"]}_count++;
-
-EOD;
-            if (in_array($entry["type"]["type"], array("data", "constdata"))) {
-                echo <<<EOD
-
-    return dest;
-
-EOD;
-            }
-
-            echo <<<EOD
-}
-
-
-EOD;
-        }
-
-        echo <<<EOD
-int {$msg["name"]}Parser_Init ({$msg["name"]}Parser *o, uint8_t *buf, int buf_len)
-{
-    ASSERT(buf_len >= 0)
-
-    o->buf = buf;
-    o->buf_len = buf_len;
-
-EOD;
-
-        foreach ($msg["entries"] as $entry) {
-            echo <<<EOD
-    o->{$entry["name"]}_start = o->buf_len;
-    o->{$entry["name"]}_span = 0;
-    o->{$entry["name"]}_pos = 0;
-
-EOD;
-        }
-
-        echo <<<EOD
-
-
-EOD;
-
-        foreach ($msg["entries"] as $entry) {
-            echo <<<EOD
-    int {$entry["name"]}_count = 0;
-
-EOD;
-        }
-
-        echo <<<EOD
-
-    int pos = 0;
-    int left = o->buf_len;
-
-    while (left > 0) {
-        int entry_pos = pos;
-
-        if (!(left >= sizeof(struct BProto_header_s))) {
-            return 0;
-        }
-        struct BProto_header_s header;
-        memcpy(&header, o->buf + pos, sizeof(header));
-        pos += sizeof(struct BProto_header_s);
-        left -= sizeof(struct BProto_header_s);
-        uint16_t type = ltoh16(header.type);
-        uint16_t id = ltoh16(header.id);
-
-        switch (type) {
-
-EOD;
-
-        foreach (array(8, 16, 32, 64) as $bits) {
-            echo <<<EOD
-            case BPROTO_TYPE_UINT{$bits}: {
-                if (!(left >= sizeof(struct BProto_uint{$bits}_s))) {
-                    return 0;
-                }
-                pos += sizeof(struct BProto_uint{$bits}_s);
-                left -= sizeof(struct BProto_uint{$bits}_s);
-
-                switch (id) {
-
-EOD;
-
-            foreach ($msg["entries"] as $entry) {
-                if (!($entry["type"]["type"] == "uint" && $entry["type"]["size"] == $bits)) {
-                    continue;
-                }
-                $type = make_type_name($msg, $entry);
-                echo <<<EOD
-                    case {$entry["id"]}:
-                        if (o->{$entry["name"]}_start == o->buf_len) {
-                            o->{$entry["name"]}_start = entry_pos;
-                        }
-                        o->{$entry["name"]}_span = pos - o->{$entry["name"]}_start;
-                        {$entry["name"]}_count++;
-                        break;
-
-EOD;
-            }
-
-            echo <<<EOD
-                    default:
-                        return 0;
-                }
-            } break;
-
-EOD;
-        }
-
-        echo <<<EOD
-            case BPROTO_TYPE_DATA:
-            case BPROTO_TYPE_CONSTDATA:
-            {
-                if (!(left >= sizeof(struct BProto_data_header_s))) {
-                    return 0;
-                }
-                struct BProto_data_header_s val;
-                memcpy(&val, o->buf + pos, sizeof(val));
-                pos += sizeof(struct BProto_data_header_s);
-                left -= sizeof(struct BProto_data_header_s);
-
-                uint32_t payload_len = ltoh32(val.len);
-                if (!(left >= payload_len)) {
-                    return 0;
-                }
-                pos += payload_len;
-                left -= payload_len;
-
-                switch (id) {
-
-EOD;
-
-        foreach ($msg["entries"] as $entry) {
-            if (!in_array($entry["type"]["type"], array("data", "constdata"))) {
-                continue;
-            }
-            $type = make_type_name($msg, $entry);
-            echo <<<EOD
-                    case {$entry["id"]}:
-                        if (!(type == {$type})) {
-                            return 0;
-                        }
-
-EOD;
-            if ($entry["type"]["type"] == "constdata") {
-                echo <<<EOD
-                        if (!(payload_len == ({$entry["type"]["size"]}))) {
-                            return 0;
-                        }
-
-EOD;
-            }
-            echo <<<EOD
-                        if (o->{$entry["name"]}_start == o->buf_len) {
-                            o->{$entry["name"]}_start = entry_pos;
-                        }
-                        o->{$entry["name"]}_span = pos - o->{$entry["name"]}_start;
-                        {$entry["name"]}_count++;
-                        break;
-
-EOD;
-        }
-
-        echo <<<EOD
-                    default:
-                        return 0;
-                }
-            } break;
-            default:
-                return 0;
-        }
-    }
-
-
-EOD;
-
-        foreach ($msg["entries"] as $entry) {
-            $cond = "";
-            switch ($entry["cardinality"]) {
-                case "repeated":
-                    break;
-                case "required repeated":
-                    $cond = "{$entry["name"]}_count >= 1";
-                    break;
-                case "optional":
-                    $cond = "{$entry["name"]}_count <= 1";
-                    break;
-                case "required":
-                    $cond = "{$entry["name"]}_count == 1";
-                    break;
-                default:
-                    assert(0);
-            }
-            if ($cond) {
-                echo <<<EOD
-    if (!({$cond})) {
-        return 0;
-    }
-
-EOD;
-            }
-        }
-
-        echo <<<EOD
-
-    return 1;
-}
-
-int {$msg["name"]}Parser_GotEverything ({$msg["name"]}Parser *o)
-{
-    return (
-
-EOD;
-
-        $first = 1;
-        foreach ($msg["entries"] as $entry) {
-            if ($first) {
-                $first = 0;
-            } else {
-                echo <<<EOD
-        &&
-
-EOD;
-            }
-            echo <<<EOD
-        o->{$entry["name"]}_pos == o->{$entry["name"]}_span
-
-EOD;
-        }
-    
-
-        echo <<<EOD
-    );
-}
-
-
-EOD;
-
-        foreach ($msg["entries"] as $entry) {
-            $decl = make_parser_decl($msg, $entry);
-            $reset_decl = make_parser_reset_decl($msg, $entry);
-            $forward_decl = make_parser_forward_decl($msg, $entry);
-            $type = make_type_name($msg, $entry);
-
-            echo <<<EOD
-{$decl}
-{
-    ASSERT(o->{$entry["name"]}_pos >= 0)
-    ASSERT(o->{$entry["name"]}_pos <= o->{$entry["name"]}_span)
-
-    int left = o->{$entry["name"]}_span - o->{$entry["name"]}_pos;
-
-    while (left > 0) {
-        ASSERT(left >= sizeof(struct BProto_header_s))
-        struct BProto_header_s header;
-        memcpy(&header, o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos, sizeof(header));
-        o->{$entry["name"]}_pos += sizeof(struct BProto_header_s);
-        left -= sizeof(struct BProto_header_s);
-        uint16_t type = ltoh16(header.type);
-        uint16_t id = ltoh16(header.id);
-
-        switch (type) {
-
-EOD;
-
-            foreach (array(8, 16, 32, 64) as $bits) {
-                echo <<<EOD
-            case BPROTO_TYPE_UINT{$bits}: {
-                ASSERT(left >= sizeof(struct BProto_uint{$bits}_s))
-
-EOD;
-                if ($entry["type"]["type"] == "uint" && $entry["type"]["size"] == $bits) {
-                    echo <<<EOD
-                struct BProto_uint{$bits}_s val;
-                memcpy(&val, o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos, sizeof(val));
-
-EOD;
-                }
-                echo <<<EOD
-                o->{$entry["name"]}_pos += sizeof(struct BProto_uint{$bits}_s);
-                left -= sizeof(struct BProto_uint{$bits}_s);
-
-EOD;
-                if ($entry["type"]["type"] == "uint" && $entry["type"]["size"] == $bits) {
-                    echo <<<EOD
-
-                if (id == {$entry["id"]}) {
-                    *v = ltoh{$bits}(val.v);
-                    return 1;
-                }
-
-EOD;
-                }
-
-                echo <<<EOD
-            } break;
-
-EOD;
-            }
-
-            echo <<<EOD
-            case BPROTO_TYPE_DATA:
-            case BPROTO_TYPE_CONSTDATA:
-            {
-                ASSERT(left >= sizeof(struct BProto_data_header_s))
-                struct BProto_data_header_s val;
-                memcpy(&val, o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos, sizeof(val));
-                o->{$entry["name"]}_pos += sizeof(struct BProto_data_header_s);
-                left -= sizeof(struct BProto_data_header_s);
-
-                uint32_t payload_len = ltoh32(val.len);
-                ASSERT(left >= payload_len)
-
-EOD;
-            if ($entry["type"]["type"] == "data" || $entry["type"]["type"] == "constdata") {
-                    echo <<<EOD
-                uint8_t *payload = o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos;
-
-EOD;
-            }
-            echo <<<EOD
-                o->{$entry["name"]}_pos += payload_len;
-                left -= payload_len;
-
-EOD;
-            if ($entry["type"]["type"] == "data") {
-                echo <<<EOD
-
-                if (type == BPROTO_TYPE_DATA && id == {$entry["id"]}) {
-                    *data = payload;
-                    *data_len = payload_len;
-                    return 1;
-                }
-
-EOD;
-            }
-            else if ($entry["type"]["type"] == "constdata") {
-                echo <<<EOD
-
-                if (type == BPROTO_TYPE_CONSTDATA && id == {$entry["id"]}) {
-                    *data = payload;
-                    return 1;
-                }
-
-EOD;
-            }
-
-            echo <<<EOD
-            } break;
-            default:
-                ASSERT(0);
-        }
-    }
-
-    return 0;
-}
-
-{$reset_decl}
-{
-    o->{$entry["name"]}_pos = 0;
-}
-
-{$forward_decl}
-{
-    o->{$entry["name"]}_pos = o->{$entry["name"]}_span;
-}
-
-
-EOD;
-        }
-    }
-
-    return ob_get_clean();
-}
diff --git a/external/badvpn_dns/client/CMakeLists.txt b/external/badvpn_dns/client/CMakeLists.txt
deleted file mode 100644
index 3cec1a9..0000000
--- a/external/badvpn_dns/client/CMakeLists.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-add_executable(badvpn-client
-    client.c
-    StreamPeerIO.c
-    DatagramPeerIO.c
-    PasswordListener.c
-    DataProto.c
-    FrameDecider.c
-    DPRelay.c
-    DPReceive.c
-    FragmentProtoDisassembler.c
-    FragmentProtoAssembler.c
-    SPProtoEncoder.c
-    SPProtoDecoder.c
-    DataProtoKeepaliveSource.c
-    PeerChat.c
-    SCOutmsgEncoder.c
-    SimpleStreamBuffer.c
-    SinglePacketSource.c
-)
-target_link_libraries(badvpn-client system flow flowextra tuntap server_conection security threadwork ${NSPR_LIBRARIES} ${NSS_LIBRARIES})
-
-install(
-    TARGETS badvpn-client
-    RUNTIME DESTINATION bin
-)
-
-install(
-    FILES badvpn-client.8
-    DESTINATION share/man/man8
-)
diff --git a/external/badvpn_dns/client/DPReceive.c b/external/badvpn_dns/client/DPReceive.c
deleted file mode 100644
index da70c74..0000000
--- a/external/badvpn_dns/client/DPReceive.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/**
- * @file DPReceive.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stddef.h>
-#include <limits.h>
-#include <string.h>
-
-#include <protocol/dataproto.h>
-#include <misc/byteorder.h>
-#include <misc/offset.h>
-#include <base/BLog.h>
-
-#include <client/DPReceive.h>
-
-#include <generated/blog_channel_DPReceive.h>
-
-static DPReceivePeer * find_peer (DPReceiveDevice *o, peerid_t id)
-{
-    for (LinkedList1Node *node = LinkedList1_GetFirst(&o->peers_list); node; node = LinkedList1Node_Next(node)) {
-        DPReceivePeer *p = UPPER_OBJECT(node, DPReceivePeer, list_node);
-        if (p->peer_id == id) {
-            return p;
-        }
-    }
-    
-    return NULL;
-}
-
-static void receiver_recv_handler_send (DPReceiveReceiver *o, uint8_t *packet, int packet_len)
-{
-    DebugObject_Access(&o->d_obj);
-    DPReceivePeer *peer = o->peer;
-    DPReceiveDevice *device = peer->device;
-    ASSERT(packet_len >= 0)
-    ASSERT(packet_len <= device->packet_mtu)
-    
-    uint8_t *data = packet;
-    int data_len = packet_len;
-    
-    int local = 0;
-    DPReceivePeer *src_peer;
-    DPReceivePeer *relay_dest_peer = NULL;
-    
-    // check header
-    if (data_len < sizeof(struct dataproto_header)) {
-        BLog(BLOG_WARNING, "no dataproto header");
-        goto out;
-    }
-    struct dataproto_header header;
-    memcpy(&header, data, sizeof(header));
-    data += sizeof(header);
-    data_len -= sizeof(header);
-    uint8_t flags = ltoh8(header.flags);
-    peerid_t from_id = ltoh16(header.from_id);
-    int num_ids = ltoh16(header.num_peer_ids);
-    
-    // check destination ID
-    if (!(num_ids == 0 || num_ids == 1)) {
-        BLog(BLOG_WARNING, "wrong number of destinations");
-        goto out;
-    }
-    peerid_t to_id = 0; // to remove warning
-    if (num_ids == 1) {
-        if (data_len < sizeof(struct dataproto_peer_id)) {
-            BLog(BLOG_WARNING, "missing destination");
-            goto out;
-        }
-        struct dataproto_peer_id id;
-        memcpy(&id, data, sizeof(id));
-        to_id = ltoh16(id.id);
-        data += sizeof(id);
-        data_len -= sizeof(id);
-    }
-    
-    // check remaining data
-    if (data_len > device->device_mtu) {
-        BLog(BLOG_WARNING, "frame too large");
-        goto out;
-    }
-    
-    // inform sink of received packet
-    if (peer->dp_sink) {
-        DataProtoSink_Received(peer->dp_sink, !!(flags & DATAPROTO_FLAGS_RECEIVING_KEEPALIVES));
-    }
-    
-    if (num_ids == 1) {
-        // find source peer
-        if (!(src_peer = find_peer(device, from_id))) {
-            BLog(BLOG_INFO, "source peer %d not known", (int)from_id);
-            goto out;
-        }
-        
-        // is frame for device or another peer?
-        if (device->have_peer_id && to_id == device->peer_id) {
-            // let the frame decider analyze the frame
-            FrameDeciderPeer_Analyze(src_peer->decider_peer, data, data_len);
-            
-            // pass frame to device
-            local = 1;
-        } else {
-            // check if relaying is allowed
-            if (!peer->is_relay_client) {
-                BLog(BLOG_WARNING, "relaying not allowed");
-                goto out;
-            }
-            
-            // provided source ID must be the peer sending the frame
-            if (src_peer != peer) {
-                BLog(BLOG_WARNING, "relay source must be the sending peer");
-                goto out;
-            }
-            
-            // find destination peer
-            DPReceivePeer *dest_peer = find_peer(device, to_id);
-            if (!dest_peer) {
-                BLog(BLOG_INFO, "relay destination peer not known");
-                goto out;
-            }
-            
-            // destination cannot be source
-            if (dest_peer == src_peer) {
-                BLog(BLOG_WARNING, "relay destination cannot be the source");
-                goto out;
-            }
-            
-            relay_dest_peer = dest_peer;
-        }
-    }
-    
-out:
-    // accept packet
-    PacketPassInterface_Done(&o->recv_if);
-    
-    // pass packet to device
-    if (local) {
-        o->device->output_func(o->device->output_func_user, data, data_len);
-    }
-    
-    // relay frame
-    if (relay_dest_peer) {
-        DPRelayRouter_SubmitFrame(&device->relay_router, &src_peer->relay_source, &relay_dest_peer->relay_sink, data, data_len, device->relay_flow_buffer_size, device->relay_flow_inactivity_time);
-    }
-}
-
-int DPReceiveDevice_Init (DPReceiveDevice *o, int device_mtu, DPReceiveDevice_output_func output_func, void *output_func_user, BReactor *reactor, int relay_flow_buffer_size, int relay_flow_inactivity_time)
-{
-    ASSERT(device_mtu >= 0)
-    ASSERT(device_mtu <= INT_MAX - DATAPROTO_MAX_OVERHEAD)
-    ASSERT(output_func)
-    ASSERT(relay_flow_buffer_size > 0)
-    
-    // init arguments
-    o->device_mtu = device_mtu;
-    o->output_func = output_func;
-    o->output_func_user = output_func_user;
-    o->reactor = reactor;
-    o->relay_flow_buffer_size = relay_flow_buffer_size;
-    o->relay_flow_inactivity_time = relay_flow_inactivity_time;
-    
-    // remember packet MTU
-    o->packet_mtu = DATAPROTO_MAX_OVERHEAD + o->device_mtu;
-    
-    // init relay router
-    if (!DPRelayRouter_Init(&o->relay_router, o->device_mtu, o->reactor)) {
-        BLog(BLOG_ERROR, "DPRelayRouter_Init failed");
-        goto fail0;
-    }
-    
-    // have no peer ID
-    o->have_peer_id = 0;
-    
-    // init peers list
-    LinkedList1_Init(&o->peers_list);
-    
-    DebugObject_Init(&o->d_obj);
-    return 1;
-    
-fail0:
-    return 0;
-}
-
-void DPReceiveDevice_Free (DPReceiveDevice *o)
-{
-    DebugObject_Free(&o->d_obj);
-    ASSERT(LinkedList1_IsEmpty(&o->peers_list))
-    
-    // free relay router
-    DPRelayRouter_Free(&o->relay_router);
-}
-
-void DPReceiveDevice_SetPeerID (DPReceiveDevice *o, peerid_t peer_id)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    // remember peer ID
-    o->peer_id = peer_id;
-    o->have_peer_id = 1;
-}
-
-void DPReceivePeer_Init (DPReceivePeer *o, DPReceiveDevice *device, peerid_t peer_id, FrameDeciderPeer *decider_peer, int is_relay_client)
-{
-    DebugObject_Access(&device->d_obj);
-    ASSERT(is_relay_client == 0 || is_relay_client == 1)
-    
-    // init arguments
-    o->device = device;
-    o->peer_id = peer_id;
-    o->decider_peer = decider_peer;
-    o->is_relay_client = is_relay_client;
-    
-    // init relay source
-    DPRelaySource_Init(&o->relay_source, &device->relay_router, o->peer_id, device->reactor);
-    
-    // init relay sink
-    DPRelaySink_Init(&o->relay_sink, o->peer_id);
-    
-    // have no sink
-    o->dp_sink = NULL;
-    
-    // insert to peers list
-    LinkedList1_Append(&device->peers_list, &o->list_node);
-    
-    DebugCounter_Init(&o->d_receivers_ctr);
-    DebugObject_Init(&o->d_obj);
-}
-
-void DPReceivePeer_Free (DPReceivePeer *o)
-{
-    DebugObject_Free(&o->d_obj);
-    DebugCounter_Free(&o->d_receivers_ctr);
-    ASSERT(!o->dp_sink)
-    
-    // remove from peers list
-    LinkedList1_Remove(&o->device->peers_list, &o->list_node);
-    
-    // free relay sink
-    DPRelaySink_Free(&o->relay_sink);
-    
-    // free relay source
-    DPRelaySource_Free(&o->relay_source);
-}
-
-void DPReceivePeer_AttachSink (DPReceivePeer *o, DataProtoSink *dp_sink)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(!o->dp_sink)
-    ASSERT(dp_sink)
-    
-    // attach relay sink
-    DPRelaySink_Attach(&o->relay_sink, dp_sink);
-    
-    o->dp_sink = dp_sink;
-}
-
-void DPReceivePeer_DetachSink (DPReceivePeer *o)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->dp_sink)
-    
-    // detach relay sink
-    DPRelaySink_Detach(&o->relay_sink);
-    
-    o->dp_sink = NULL;
-}
-
-void DPReceiveReceiver_Init (DPReceiveReceiver *o, DPReceivePeer *peer)
-{
-    DebugObject_Access(&peer->d_obj);
-    DPReceiveDevice *device = peer->device;
-    
-    // init arguments
-    o->peer = peer;
-    
-    // remember device
-    o->device = device;
-    
-    // init receive interface
-    PacketPassInterface_Init(&o->recv_if, device->packet_mtu, (PacketPassInterface_handler_send)receiver_recv_handler_send, o, BReactor_PendingGroup(device->reactor));
-    
-    DebugCounter_Increment(&peer->d_receivers_ctr);
-    DebugObject_Init(&o->d_obj);
-}
-
-void DPReceiveReceiver_Free (DPReceiveReceiver *o)
-{
-    DebugObject_Free(&o->d_obj);
-    DebugCounter_Decrement(&o->peer->d_receivers_ctr);
-    
-    // free receive interface
-    PacketPassInterface_Free(&o->recv_if);
-}
-
-PacketPassInterface * DPReceiveReceiver_GetInput (DPReceiveReceiver *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->recv_if;
-}
diff --git a/external/badvpn_dns/client/DPReceive.h b/external/badvpn_dns/client/DPReceive.h
deleted file mode 100644
index ecc5a05..0000000
--- a/external/badvpn_dns/client/DPReceive.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/**
- * @file DPReceive.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Receive processing for the VPN client.
- */
-
-#ifndef BADVPN_CLIENT_DPRECEIVE_H
-#define BADVPN_CLIENT_DPRECEIVE_H
-
-#include <protocol/scproto.h>
-#include <misc/debugcounter.h>
-#include <misc/debug.h>
-#include <structure/LinkedList1.h>
-#include <base/DebugObject.h>
-#include <client/DataProto.h>
-#include <client/DPRelay.h>
-#include <client/FrameDecider.h>
-
-typedef void (*DPReceiveDevice_output_func) (void *output_user, uint8_t *data, int data_len);
-
-struct DPReceiveReceiver_s;
-
-typedef struct {
-    int device_mtu;
-    DPReceiveDevice_output_func output_func;
-    void *output_func_user;
-    BReactor *reactor;
-    int relay_flow_buffer_size;
-    int relay_flow_inactivity_time;
-    int packet_mtu;
-    DPRelayRouter relay_router;
-    int have_peer_id;
-    peerid_t peer_id;
-    LinkedList1 peers_list;
-    DebugObject d_obj;
-} DPReceiveDevice;
-
-typedef struct {
-    DPReceiveDevice *device;
-    peerid_t peer_id;
-    FrameDeciderPeer *decider_peer;
-    int is_relay_client;
-    DPRelaySource relay_source;
-    DPRelaySink relay_sink;
-    DataProtoSink *dp_sink;
-    LinkedList1Node list_node;
-    DebugObject d_obj;
-    DebugCounter d_receivers_ctr;
-} DPReceivePeer;
-
-typedef struct DPReceiveReceiver_s {
-    DPReceivePeer *peer;
-    DPReceiveDevice *device;
-    PacketPassInterface recv_if;
-    DebugObject d_obj;
-} DPReceiveReceiver;
-
-int DPReceiveDevice_Init (DPReceiveDevice *o, int device_mtu, DPReceiveDevice_output_func output_func, void *output_func_user, BReactor *reactor, int relay_flow_buffer_size, int relay_flow_inactivity_time) WARN_UNUSED;
-void DPReceiveDevice_Free (DPReceiveDevice *o);
-void DPReceiveDevice_SetPeerID (DPReceiveDevice *o, peerid_t peer_id);
-
-void DPReceivePeer_Init (DPReceivePeer *o, DPReceiveDevice *device, peerid_t peer_id, FrameDeciderPeer *decider_peer, int is_relay_client);
-void DPReceivePeer_Free (DPReceivePeer *o);
-void DPReceivePeer_AttachSink (DPReceivePeer *o, DataProtoSink *dp_sink);
-void DPReceivePeer_DetachSink (DPReceivePeer *o);
-
-void DPReceiveReceiver_Init (DPReceiveReceiver *o, DPReceivePeer *peer);
-void DPReceiveReceiver_Free (DPReceiveReceiver *o);
-PacketPassInterface * DPReceiveReceiver_GetInput (DPReceiveReceiver *o);
-
-#endif
diff --git a/external/badvpn_dns/client/DPRelay.c b/external/badvpn_dns/client/DPRelay.c
deleted file mode 100644
index 983e3ad..0000000
--- a/external/badvpn_dns/client/DPRelay.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/**
- * @file DPRelay.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <misc/offset.h>
-#include <base/BLog.h>
-
-#include <client/DPRelay.h>
-
-#include <generated/blog_channel_DPRelay.h>
-
-static void flow_inactivity_handler (struct DPRelay_flow *flow);
-
-static struct DPRelay_flow * create_flow (DPRelaySource *src, DPRelaySink *sink, int num_packets, int inactivity_time)
-{
-    ASSERT(num_packets > 0)
-    
-    // allocate structure
-    struct DPRelay_flow *flow = (struct DPRelay_flow *)malloc(sizeof(*flow));
-    if (!flow) {
-        BLog(BLOG_ERROR, "relay flow %d->%d: malloc failed", (int)src->source_id, (int)sink->dest_id);
-        goto fail0;
-    }
-    
-    // set src and sink
-    flow->src = src;
-    flow->sink = sink;
-    
-    // init DataProtoFlow
-    if (!DataProtoFlow_Init(&flow->dp_flow, &src->router->dp_source, src->source_id, sink->dest_id, num_packets, inactivity_time, flow, (DataProtoFlow_handler_inactivity)flow_inactivity_handler)) {
-        BLog(BLOG_ERROR, "relay flow %d->%d: DataProtoFlow_Init failed", (int)src->source_id, (int)sink->dest_id);
-        goto fail1;
-    }
-    
-    // insert to source list
-    LinkedList1_Append(&src->flows_list, &flow->src_list_node);
-    
-    // insert to sink list
-    LinkedList1_Append(&sink->flows_list, &flow->sink_list_node);
-    
-    // attach flow if needed
-    if (sink->dp_sink) {
-        DataProtoFlow_Attach(&flow->dp_flow, sink->dp_sink);
-    }
-    
-    BLog(BLOG_INFO, "relay flow %d->%d: created", (int)src->source_id, (int)sink->dest_id);
-    
-    return flow;
-    
-fail1:
-    free(flow);
-fail0:
-    return NULL;
-}
-
-static void free_flow (struct DPRelay_flow *flow)
-{
-    // detach flow if needed
-    if (flow->sink->dp_sink) {
-        DataProtoFlow_Detach(&flow->dp_flow);
-    }
-    
-    // remove posible router reference
-    if (flow->src->router->current_flow == flow) {
-        flow->src->router->current_flow = NULL;
-    }
-    
-    // remove from sink list
-    LinkedList1_Remove(&flow->sink->flows_list, &flow->sink_list_node);
-    
-    // remove from source list
-    LinkedList1_Remove(&flow->src->flows_list, &flow->src_list_node);
-    
-    // free DataProtoFlow
-    DataProtoFlow_Free(&flow->dp_flow);
-    
-    // free structore
-    free(flow);
-}
-
-static void flow_inactivity_handler (struct DPRelay_flow *flow)
-{
-    BLog(BLOG_INFO, "relay flow %d->%d: timed out", (int)flow->src->source_id, (int)flow->sink->dest_id);
-    
-    free_flow(flow);
-}
-
-static struct DPRelay_flow * source_find_flow (DPRelaySource *o, DPRelaySink *sink)
-{
-    for (LinkedList1Node *node = LinkedList1_GetFirst(&o->flows_list); node; node = LinkedList1Node_Next(node)) {
-        struct DPRelay_flow *flow = UPPER_OBJECT(node, struct DPRelay_flow, src_list_node);
-        ASSERT(flow->src == o)
-        if (flow->sink == sink) {
-            return flow;
-        }
-    }
-    
-    return NULL;
-}
-
-static void router_dp_source_handler (DPRelayRouter *o, const uint8_t *frame, int frame_len)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    if (!o->current_flow) {
-        return;
-    }
-    
-    // route frame to current flow
-    DataProtoFlow_Route(&o->current_flow->dp_flow, 0);
-    
-    // set no current flow
-    o->current_flow = NULL;
-}
-
-int DPRelayRouter_Init (DPRelayRouter *o, int frame_mtu, BReactor *reactor)
-{
-    ASSERT(frame_mtu >= 0)
-    ASSERT(frame_mtu <= INT_MAX - DATAPROTO_MAX_OVERHEAD)
-    
-    // init arguments
-    o->frame_mtu = frame_mtu;
-    
-    // init BufferWriter
-    BufferWriter_Init(&o->writer, frame_mtu, BReactor_PendingGroup(reactor));
-    
-    // init DataProtoSource
-    if (!DataProtoSource_Init(&o->dp_source, BufferWriter_GetOutput(&o->writer), (DataProtoSource_handler)router_dp_source_handler, o, reactor)) {
-        BLog(BLOG_ERROR, "DataProtoSource_Init failed");
-        goto fail1;
-    }
-    
-    // have no current flow
-    o->current_flow = NULL;
-    
-    DebugCounter_Init(&o->d_ctr);
-    DebugObject_Init(&o->d_obj);
-    return 1;
-    
-fail1:
-    BufferWriter_Free(&o->writer);
-    return 0;
-}
-
-void DPRelayRouter_Free (DPRelayRouter *o)
-{
-    DebugObject_Free(&o->d_obj);
-    DebugCounter_Free(&o->d_ctr);
-    ASSERT(!o->current_flow) // have no sources
-    
-    // free DataProtoSource
-    DataProtoSource_Free(&o->dp_source);
-    
-    // free BufferWriter
-    BufferWriter_Free(&o->writer);
-}
-
-void DPRelayRouter_SubmitFrame (DPRelayRouter *o, DPRelaySource *src, DPRelaySink *sink, uint8_t *data, int data_len, int num_packets, int inactivity_time)
-{
-    DebugObject_Access(&o->d_obj);
-    DebugObject_Access(&src->d_obj);
-    DebugObject_Access(&sink->d_obj);
-    ASSERT(!o->current_flow)
-    ASSERT(src->router == o)
-    ASSERT(data_len >= 0)
-    ASSERT(data_len <= o->frame_mtu)
-    ASSERT(num_packets > 0)
-    
-    // get memory location
-    uint8_t *out;
-    if (!BufferWriter_StartPacket(&o->writer, &out)) {
-        BLog(BLOG_ERROR, "BufferWriter_StartPacket failed for frame %d->%d !?", (int)src->source_id, (int)sink->dest_id);
-        return;
-    }
-    
-    // write frame
-    memcpy(out, data, data_len);
-    
-    // submit frame
-    BufferWriter_EndPacket(&o->writer, data_len);
-    
-    // get a flow
-    // this comes _after_ writing the packet, in case flow initialization schedules jobs
-    struct DPRelay_flow *flow = source_find_flow(src, sink);
-    if (!flow) {
-        if (!(flow = create_flow(src, sink, num_packets, inactivity_time))) {
-            return;
-        }
-    }
-    
-    // remember flow so we know where to route the frame in router_dp_source_handler
-    o->current_flow = flow;
-}
-
-void DPRelaySource_Init (DPRelaySource *o, DPRelayRouter *router, peerid_t source_id, BReactor *reactor)
-{
-    DebugObject_Access(&router->d_obj);
-    
-    // init arguments
-    o->router = router;
-    o->source_id = source_id;
-    
-    // init flows list
-    LinkedList1_Init(&o->flows_list);
-    
-    DebugCounter_Increment(&o->router->d_ctr);
-    DebugObject_Init(&o->d_obj);
-}
-
-void DPRelaySource_Free (DPRelaySource *o)
-{
-    DebugObject_Free(&o->d_obj);
-    DebugCounter_Decrement(&o->router->d_ctr);
-    
-    // free flows, detaching them if needed
-    LinkedList1Node *node;
-    while (node = LinkedList1_GetFirst(&o->flows_list)) {
-        struct DPRelay_flow *flow = UPPER_OBJECT(node, struct DPRelay_flow, src_list_node);
-        free_flow(flow);
-    }
-}
-
-void DPRelaySink_Init (DPRelaySink *o, peerid_t dest_id)
-{
-    // init arguments
-    o->dest_id = dest_id;
-    
-    // init flows list
-    LinkedList1_Init(&o->flows_list);
-    
-    // have no sink
-    o->dp_sink = NULL;
-    
-    DebugObject_Init(&o->d_obj);
-}
-
-void DPRelaySink_Free (DPRelaySink *o)
-{
-    DebugObject_Free(&o->d_obj);
-    ASSERT(!o->dp_sink)
-    
-    // free flows
-    LinkedList1Node *node;
-    while (node = LinkedList1_GetFirst(&o->flows_list)) {
-        struct DPRelay_flow *flow = UPPER_OBJECT(node, struct DPRelay_flow, sink_list_node);
-        free_flow(flow);
-    }
-}
-
-void DPRelaySink_Attach (DPRelaySink *o, DataProtoSink *dp_sink)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(!o->dp_sink)
-    ASSERT(dp_sink)
-    
-    // attach flows
-    for (LinkedList1Node *node = LinkedList1_GetFirst(&o->flows_list); node; node = LinkedList1Node_Next(node)) {
-        struct DPRelay_flow *flow = UPPER_OBJECT(node, struct DPRelay_flow, sink_list_node);
-        DataProtoFlow_Attach(&flow->dp_flow, dp_sink);
-    }
-    
-    // set sink
-    o->dp_sink = dp_sink;
-}
-
-void DPRelaySink_Detach (DPRelaySink *o)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->dp_sink)
-    
-    // detach flows
-    for (LinkedList1Node *node = LinkedList1_GetFirst(&o->flows_list); node; node = LinkedList1Node_Next(node)) {
-        struct DPRelay_flow *flow = UPPER_OBJECT(node, struct DPRelay_flow, sink_list_node);
-        DataProtoFlow_Detach(&flow->dp_flow);
-    }
-    
-    // set no sink
-    o->dp_sink = NULL;
-}
diff --git a/external/badvpn_dns/client/DPRelay.h b/external/badvpn_dns/client/DPRelay.h
deleted file mode 100644
index c5e16eb..0000000
--- a/external/badvpn_dns/client/DPRelay.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * @file DPRelay.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BADVPN_CLIENT_DPRELAY_H
-#define BADVPN_CLIENT_DPRELAY_H
-
-#include <stdint.h>
-#include <limits.h>
-
-#include <protocol/scproto.h>
-#include <protocol/dataproto.h>
-#include <misc/debug.h>
-#include <structure/LinkedList1.h>
-#include <base/DebugObject.h>
-#include <flow/BufferWriter.h>
-#include <client/DataProto.h>
-
-struct DPRelay_flow;
-
-typedef struct {
-    int frame_mtu;
-    BufferWriter writer;
-    DataProtoSource dp_source;
-    struct DPRelay_flow *current_flow;
-    DebugObject d_obj;
-    DebugCounter d_ctr;
-} DPRelayRouter;
-
-typedef struct {
-    DPRelayRouter *router;
-    peerid_t source_id;
-    LinkedList1 flows_list;
-    DebugObject d_obj;
-} DPRelaySource;
-
-typedef struct {
-    peerid_t dest_id;
-    LinkedList1 flows_list;
-    DataProtoSink *dp_sink;
-    DebugObject d_obj;
-} DPRelaySink;
-
-struct DPRelay_flow {
-    DPRelaySource *src;
-    DPRelaySink *sink;
-    DataProtoFlow dp_flow;
-    LinkedList1Node src_list_node;
-    LinkedList1Node sink_list_node;
-};
-
-int DPRelayRouter_Init (DPRelayRouter *o, int frame_mtu, BReactor *reactor) WARN_UNUSED;
-void DPRelayRouter_Free (DPRelayRouter *o);
-void DPRelayRouter_SubmitFrame (DPRelayRouter *o, DPRelaySource *src, DPRelaySink *sink, uint8_t *data, int data_len, int num_packets, int inactivity_time);
-
-void DPRelaySource_Init (DPRelaySource *o, DPRelayRouter *router, peerid_t source_id, BReactor *reactor);
-void DPRelaySource_Free (DPRelaySource *o);
-
-void DPRelaySink_Init (DPRelaySink *o, peerid_t dest_id);
-void DPRelaySink_Free (DPRelaySink *o);
-void DPRelaySink_Attach (DPRelaySink *o, DataProtoSink *dp_sink);
-void DPRelaySink_Detach (DPRelaySink *o);
-
-#endif
diff --git a/external/badvpn_dns/client/DataProto.c b/external/badvpn_dns/client/DataProto.c
deleted file mode 100644
index 255045a..0000000
--- a/external/badvpn_dns/client/DataProto.c
+++ /dev/null
@@ -1,566 +0,0 @@
-/**
- * @file DataProto.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-
-#include <protocol/dataproto.h>
-#include <misc/byteorder.h>
-#include <base/BLog.h>
-
-#include <client/DataProto.h>
-
-#include <generated/blog_channel_DataProto.h>
-
-static void monitor_handler (DataProtoSink *o);
-static void refresh_up_job (DataProtoSink *o);
-static void receive_timer_handler (DataProtoSink *o);
-static void notifier_handler (DataProtoSink *o, uint8_t *data, int data_len);
-static void up_job_handler (DataProtoSink *o);
-static void flow_buffer_free (struct DataProtoFlow_buffer *b);
-static void flow_buffer_attach (struct DataProtoFlow_buffer *b, DataProtoSink *sink);
-static void flow_buffer_detach (struct DataProtoFlow_buffer *b);
-static void flow_buffer_schedule_detach (struct DataProtoFlow_buffer *b);
-static void flow_buffer_finish_detach (struct DataProtoFlow_buffer *b);
-static void flow_buffer_qflow_handler_busy (struct DataProtoFlow_buffer *b);
-
-void monitor_handler (DataProtoSink *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    // send keep-alive
-    PacketRecvBlocker_AllowBlockedPacket(&o->ka_blocker);
-}
-
-void refresh_up_job (DataProtoSink *o)
-{
-    if (o->up != o->up_report) {
-        BPending_Set(&o->up_job);
-    } else {
-        BPending_Unset(&o->up_job);
-    }
-}
-
-void receive_timer_handler (DataProtoSink *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    // consider down
-    o->up = 0;
-    
-    refresh_up_job(o);
-}
-
-void notifier_handler (DataProtoSink *o, uint8_t *data, int data_len)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(data_len >= sizeof(struct dataproto_header))
-    
-    int flags = 0;
-    
-    // if we are receiving keepalives, set the flag
-    if (BTimer_IsRunning(&o->receive_timer)) {
-        flags |= DATAPROTO_FLAGS_RECEIVING_KEEPALIVES;
-    }
-    
-    // modify existing packet here
-    struct dataproto_header header;
-    memcpy(&header, data, sizeof(header));
-    header.flags = hton8(flags);
-    memcpy(data, &header, sizeof(header));
-}
-
-void up_job_handler (DataProtoSink *o)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->up != o->up_report)
-    
-    o->up_report = o->up;
-    
-    o->handler(o->user, o->up);
-    return;
-}
-
-void source_router_handler (DataProtoSource *o, uint8_t *buf, int recv_len)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(buf)
-    ASSERT(recv_len >= 0)
-    ASSERT(recv_len <= o->frame_mtu)
-    
-    // remember packet
-    o->current_buf = buf;
-    o->current_recv_len = recv_len;
-    
-    // call handler
-    o->handler(o->user, buf + DATAPROTO_MAX_OVERHEAD, recv_len);
-    return;
-}
-
-void flow_buffer_free (struct DataProtoFlow_buffer *b)
-{
-    ASSERT(!b->sink)
-    
-    // free route buffer
-    RouteBuffer_Free(&b->rbuf);
-    
-    // free inactivity monitor
-    if (b->inactivity_time >= 0) {
-        PacketPassInactivityMonitor_Free(&b->monitor);
-    }
-    
-    // free connector
-    PacketPassConnector_Free(&b->connector);
-    
-    // free buffer structure
-    free(b);
-}
-
-void flow_buffer_attach (struct DataProtoFlow_buffer *b, DataProtoSink *sink)
-{
-    ASSERT(!b->sink)
-    
-    // init queue flow
-    PacketPassFairQueueFlow_Init(&b->sink_qflow, &sink->queue);
-    
-    // connect to queue flow
-    PacketPassConnector_ConnectOutput(&b->connector, PacketPassFairQueueFlow_GetInput(&b->sink_qflow));
-    
-    // set DataProto
-    b->sink = sink;
-}
-
-void flow_buffer_detach (struct DataProtoFlow_buffer *b)
-{
-    ASSERT(b->sink)
-    PacketPassFairQueueFlow_AssertFree(&b->sink_qflow);
-    
-    // disconnect from queue flow
-    PacketPassConnector_DisconnectOutput(&b->connector);
-    
-    // free queue flow
-    PacketPassFairQueueFlow_Free(&b->sink_qflow);
-    
-    // clear reference to this buffer in the sink
-    if (b->sink->detaching_buffer == b) {
-        b->sink->detaching_buffer = NULL;
-    }
-    
-    // set no DataProto
-    b->sink = NULL;
-}
-
-void flow_buffer_schedule_detach (struct DataProtoFlow_buffer *b)
-{
-    ASSERT(b->sink)
-    ASSERT(PacketPassFairQueueFlow_IsBusy(&b->sink_qflow))
-    ASSERT(!b->sink->detaching_buffer || b->sink->detaching_buffer == b)
-    
-    if (b->sink->detaching_buffer == b) {
-        return;
-    }
-    
-    // request cancel
-    PacketPassFairQueueFlow_RequestCancel(&b->sink_qflow);
-    
-    // set busy handler
-    PacketPassFairQueueFlow_SetBusyHandler(&b->sink_qflow, (PacketPassFairQueue_handler_busy)flow_buffer_qflow_handler_busy, b);
-    
-    // remember this buffer in the sink so it can handle us if it goes away
-    b->sink->detaching_buffer = b;
-}
-
-void flow_buffer_finish_detach (struct DataProtoFlow_buffer *b)
-{
-    ASSERT(b->sink)
-    ASSERT(b->sink->detaching_buffer == b)
-    PacketPassFairQueueFlow_AssertFree(&b->sink_qflow);
-    
-    // detach
-    flow_buffer_detach(b);
-    
-    if (!b->flow) {
-        // free
-        flow_buffer_free(b);
-    } else if (b->flow->sink_desired) {
-        // attach
-        flow_buffer_attach(b, b->flow->sink_desired);
-    }
-}
-
-void flow_buffer_qflow_handler_busy (struct DataProtoFlow_buffer *b)
-{
-    ASSERT(b->sink)
-    ASSERT(b->sink->detaching_buffer == b)
-    PacketPassFairQueueFlow_AssertFree(&b->sink_qflow);
-    
-    flow_buffer_finish_detach(b);
-}
-
-int DataProtoSink_Init (DataProtoSink *o, BReactor *reactor, PacketPassInterface *output, btime_t keepalive_time, btime_t tolerance_time, DataProtoSink_handler handler, void *user)
-{
-    ASSERT(PacketPassInterface_HasCancel(output))
-    ASSERT(PacketPassInterface_GetMTU(output) >= DATAPROTO_MAX_OVERHEAD)
-    
-    // init arguments
-    o->reactor = reactor;
-    o->handler = handler;
-    o->user = user;
-    
-    // set frame MTU
-    o->frame_mtu = PacketPassInterface_GetMTU(output) - DATAPROTO_MAX_OVERHEAD;
-    
-    // init notifier
-    PacketPassNotifier_Init(&o->notifier, output, BReactor_PendingGroup(o->reactor));
-    PacketPassNotifier_SetHandler(&o->notifier, (PacketPassNotifier_handler_notify)notifier_handler, o);
-    
-    // init monitor
-    PacketPassInactivityMonitor_Init(&o->monitor, PacketPassNotifier_GetInput(&o->notifier), o->reactor, keepalive_time, (PacketPassInactivityMonitor_handler)monitor_handler, o);
-    PacketPassInactivityMonitor_Force(&o->monitor);
-    
-    // init queue
-    if (!PacketPassFairQueue_Init(&o->queue, PacketPassInactivityMonitor_GetInput(&o->monitor), BReactor_PendingGroup(o->reactor), 1, 1)) {
-        BLog(BLOG_ERROR, "PacketPassFairQueue_Init failed");
-        goto fail1;
-    }
-    
-    // init keepalive queue flow
-    PacketPassFairQueueFlow_Init(&o->ka_qflow, &o->queue);
-    
-    // init keepalive source
-    DataProtoKeepaliveSource_Init(&o->ka_source, BReactor_PendingGroup(o->reactor));
-    
-    // init keepalive blocker
-    PacketRecvBlocker_Init(&o->ka_blocker, DataProtoKeepaliveSource_GetOutput(&o->ka_source), BReactor_PendingGroup(o->reactor));
-    
-    // init keepalive buffer
-    if (!SinglePacketBuffer_Init(&o->ka_buffer, PacketRecvBlocker_GetOutput(&o->ka_blocker), PacketPassFairQueueFlow_GetInput(&o->ka_qflow), BReactor_PendingGroup(o->reactor))) {
-        BLog(BLOG_ERROR, "SinglePacketBuffer_Init failed");
-        goto fail2;
-    }
-    
-    // init receive timer
-    BTimer_Init(&o->receive_timer, tolerance_time, (BTimer_handler)receive_timer_handler, o);
-    
-    // init handler job
-    BPending_Init(&o->up_job, BReactor_PendingGroup(o->reactor), (BPending_handler)up_job_handler, o);
-    
-    // set not up
-    o->up = 0;
-    o->up_report = 0;
-    
-    // set no detaching buffer
-    o->detaching_buffer = NULL;
-    
-    DebugCounter_Init(&o->d_ctr);
-    DebugObject_Init(&o->d_obj);
-    return 1;
-    
-fail2:
-    PacketRecvBlocker_Free(&o->ka_blocker);
-    DataProtoKeepaliveSource_Free(&o->ka_source);
-    PacketPassFairQueueFlow_Free(&o->ka_qflow);
-    PacketPassFairQueue_Free(&o->queue);
-fail1:
-    PacketPassInactivityMonitor_Free(&o->monitor);
-    PacketPassNotifier_Free(&o->notifier);
-    return 0;
-}
-
-void DataProtoSink_Free (DataProtoSink *o)
-{
-    DebugObject_Free(&o->d_obj);
-    DebugCounter_Free(&o->d_ctr);
-    
-    // allow freeing queue flows
-    PacketPassFairQueue_PrepareFree(&o->queue);
-    
-    // release detaching buffer
-    if (o->detaching_buffer) {
-        ASSERT(!o->detaching_buffer->flow || o->detaching_buffer->flow->sink_desired != o)
-        flow_buffer_finish_detach(o->detaching_buffer);
-    }
-    
-    // free handler job
-    BPending_Free(&o->up_job);
-    
-    // free receive timer
-    BReactor_RemoveTimer(o->reactor, &o->receive_timer);
-    
-    // free keepalive buffer
-    SinglePacketBuffer_Free(&o->ka_buffer);
-    
-    // free keepalive blocker
-    PacketRecvBlocker_Free(&o->ka_blocker);
-    
-    // free keepalive source
-    DataProtoKeepaliveSource_Free(&o->ka_source);
-    
-    // free keepalive queue flow
-    PacketPassFairQueueFlow_Free(&o->ka_qflow);
-    
-    // free queue
-    PacketPassFairQueue_Free(&o->queue);
-    
-    // free monitor
-    PacketPassInactivityMonitor_Free(&o->monitor);
-    
-    // free notifier
-    PacketPassNotifier_Free(&o->notifier);
-}
-
-void DataProtoSink_Received (DataProtoSink *o, int peer_receiving)
-{
-    ASSERT(peer_receiving == 0 || peer_receiving == 1)
-    DebugObject_Access(&o->d_obj);
-    
-    // reset receive timer
-    BReactor_SetTimer(o->reactor, &o->receive_timer);
-    
-    if (!peer_receiving) {
-        // peer reports not receiving, consider down
-        o->up = 0;
-        // send keep-alive to converge faster
-        PacketRecvBlocker_AllowBlockedPacket(&o->ka_blocker);
-    } else {
-        // consider up
-        o->up = 1;
-    }
-    
-    refresh_up_job(o);
-}
-
-int DataProtoSource_Init (DataProtoSource *o, PacketRecvInterface *input, DataProtoSource_handler handler, void *user, BReactor *reactor)
-{
-    ASSERT(PacketRecvInterface_GetMTU(input) <= INT_MAX - DATAPROTO_MAX_OVERHEAD)
-    ASSERT(handler)
-    
-    // init arguments
-    o->handler = handler;
-    o->user = user;
-    o->reactor = reactor;
-    
-    // remember frame MTU
-    o->frame_mtu = PacketRecvInterface_GetMTU(input);
-    
-    // init router
-    if (!PacketRouter_Init(&o->router, DATAPROTO_MAX_OVERHEAD + o->frame_mtu, DATAPROTO_MAX_OVERHEAD, input, (PacketRouter_handler)source_router_handler, o, BReactor_PendingGroup(reactor))) {
-        BLog(BLOG_ERROR, "PacketRouter_Init failed");
-        goto fail0;
-    }
-    
-    DebugCounter_Init(&o->d_ctr);
-    DebugObject_Init(&o->d_obj);
-    return 1;
-    
-fail0:
-    return 0;
-}
-
-void DataProtoSource_Free (DataProtoSource *o)
-{
-    DebugObject_Free(&o->d_obj);
-    DebugCounter_Free(&o->d_ctr);
-    
-    // free router
-    PacketRouter_Free(&o->router);
-}
-
-int DataProtoFlow_Init (DataProtoFlow *o, DataProtoSource *source, peerid_t source_id, peerid_t dest_id, int num_packets, int inactivity_time, void *user,
-                        DataProtoFlow_handler_inactivity handler_inactivity)
-{
-    DebugObject_Access(&source->d_obj);
-    ASSERT(num_packets > 0)
-    ASSERT(!(inactivity_time >= 0) || handler_inactivity)
-    
-    // init arguments
-    o->source = source;
-    o->source_id = source_id;
-    o->dest_id = dest_id;
-    
-    // set no desired sink
-    o->sink_desired = NULL;
-    
-    // allocate buffer structure
-    struct DataProtoFlow_buffer *b = (struct DataProtoFlow_buffer *)malloc(sizeof(*b));
-    if (!b) {
-        BLog(BLOG_ERROR, "malloc failed");
-        goto fail0;
-    }
-    o->b = b;
-    
-    // set parent
-    b->flow = o;
-    
-    // remember inactivity time
-    b->inactivity_time = inactivity_time;
-    
-    // init connector
-    PacketPassConnector_Init(&b->connector, DATAPROTO_MAX_OVERHEAD + source->frame_mtu, BReactor_PendingGroup(source->reactor));
-    
-    // init inactivity monitor
-    PacketPassInterface *buf_out = PacketPassConnector_GetInput(&b->connector);
-    if (b->inactivity_time >= 0) {
-        PacketPassInactivityMonitor_Init(&b->monitor, buf_out, source->reactor, b->inactivity_time, handler_inactivity, user);
-        buf_out = PacketPassInactivityMonitor_GetInput(&b->monitor);
-    }
-    
-    // init route buffer
-    if (!RouteBuffer_Init(&b->rbuf, DATAPROTO_MAX_OVERHEAD + source->frame_mtu, buf_out, num_packets)) {
-        BLog(BLOG_ERROR, "RouteBuffer_Init failed");
-        goto fail1;
-    }
-    
-    // set no sink
-    b->sink = NULL;
-    
-    DebugCounter_Increment(&source->d_ctr);
-    DebugObject_Init(&o->d_obj);
-    return 1;
-    
-fail1:
-    if (b->inactivity_time >= 0) {
-        PacketPassInactivityMonitor_Free(&b->monitor);
-    }
-    PacketPassConnector_Free(&b->connector);
-    free(b);
-fail0:
-    return 0;
-}
-
-void DataProtoFlow_Free (DataProtoFlow *o)
-{
-    DebugObject_Free(&o->d_obj);
-    DebugCounter_Decrement(&o->source->d_ctr);
-    ASSERT(!o->sink_desired)
-    struct DataProtoFlow_buffer *b = o->b;
-    
-    if (b->sink) {
-        if (PacketPassFairQueueFlow_IsBusy(&b->sink_qflow)) {
-            // schedule detach, free buffer after detach
-            flow_buffer_schedule_detach(b);
-            b->flow = NULL;
-            
-            // remove inactivity handler
-            if (b->inactivity_time >= 0) {
-                PacketPassInactivityMonitor_SetHandler(&b->monitor, NULL, NULL);
-            }
-        } else {
-            // detach and free buffer now
-            flow_buffer_detach(b);
-            flow_buffer_free(b);
-        }
-    } else {
-        // free buffer
-        flow_buffer_free(b);
-    }
-}
-
-void DataProtoFlow_Route (DataProtoFlow *o, int more)
-{
-    DebugObject_Access(&o->d_obj);
-    PacketRouter_AssertRoute(&o->source->router);
-    ASSERT(o->source->current_buf)
-    ASSERT(more == 0 || more == 1)
-    struct DataProtoFlow_buffer *b = o->b;
-    
-    // write header. Don't set flags, it will be set in notifier_handler.
-    struct dataproto_header header;
-    struct dataproto_peer_id id;
-    header.from_id = htol16(o->source_id);
-    header.num_peer_ids = htol16(1);
-    id.id = htol16(o->dest_id);
-    memcpy(o->source->current_buf, &header, sizeof(header));
-    memcpy(o->source->current_buf + sizeof(header), &id, sizeof(id));
-    
-    // route
-    uint8_t *next_buf;
-    if (!PacketRouter_Route(&o->source->router, DATAPROTO_MAX_OVERHEAD + o->source->current_recv_len, &b->rbuf,
-                            &next_buf, DATAPROTO_MAX_OVERHEAD, (more ? o->source->current_recv_len : 0)
-    )) {
-        BLog(BLOG_NOTICE, "buffer full: %d->%d", (int)o->source_id, (int)o->dest_id);
-        return;
-    }
-    
-    // remember next buffer, or don't allow further routing if more==0
-    o->source->current_buf = (more ? next_buf : NULL);
-}
-
-void DataProtoFlow_Attach (DataProtoFlow *o, DataProtoSink *sink)
-{
-    DebugObject_Access(&o->d_obj);
-    DebugObject_Access(&sink->d_obj);
-    ASSERT(!o->sink_desired)
-    ASSERT(sink)
-    ASSERT(o->source->frame_mtu <= sink->frame_mtu)
-    struct DataProtoFlow_buffer *b = o->b;
-    
-    if (b->sink) {
-        if (PacketPassFairQueueFlow_IsBusy(&b->sink_qflow)) {
-            // schedule detach and reattach
-            flow_buffer_schedule_detach(b);
-        } else {
-            // detach and reattach now
-            flow_buffer_detach(b);
-            flow_buffer_attach(b, sink);
-        }
-    } else {
-        // attach
-        flow_buffer_attach(b, sink);
-    }
-    
-    // set desired sink
-    o->sink_desired = sink;
-    
-    DebugCounter_Increment(&sink->d_ctr);
-}
-
-void DataProtoFlow_Detach (DataProtoFlow *o)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->sink_desired)
-    struct DataProtoFlow_buffer *b = o->b;
-    ASSERT(b->sink)
-    
-    DataProtoSink *sink = o->sink_desired;
-    
-    if (PacketPassFairQueueFlow_IsBusy(&b->sink_qflow)) {
-        // schedule detach
-        flow_buffer_schedule_detach(b);
-    } else {
-        // detach now
-        flow_buffer_detach(b);
-    }
-    
-    // set no desired sink
-    o->sink_desired = NULL;
-    
-    DebugCounter_Decrement(&sink->d_ctr);
-}
diff --git a/external/badvpn_dns/client/DataProto.h b/external/badvpn_dns/client/DataProto.h
deleted file mode 100644
index 0da3a20..0000000
--- a/external/badvpn_dns/client/DataProto.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/**
- * @file DataProto.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Mudule for frame sending used in the VPN client program.
- */
-
-#ifndef BADVPN_CLIENT_DATAPROTO_H
-#define BADVPN_CLIENT_DATAPROTO_H
-
-#include <stdint.h>
-
-#include <misc/debugcounter.h>
-#include <misc/debug.h>
-#include <base/DebugObject.h>
-#include <system/BReactor.h>
-#include <flow/PacketPassFairQueue.h>
-#include <flow/PacketPassNotifier.h>
-#include <flow/PacketRecvBlocker.h>
-#include <flow/SinglePacketBuffer.h>
-#include <flow/PacketPassConnector.h>
-#include <flow/PacketRouter.h>
-#include <flowextra/PacketPassInactivityMonitor.h>
-#include <client/DataProtoKeepaliveSource.h>
-
-typedef void (*DataProtoSink_handler) (void *user, int up);
-typedef void (*DataProtoSource_handler) (void *user, const uint8_t *frame, int frame_len);
-typedef void (*DataProtoFlow_handler_inactivity) (void *user);
-
-struct DataProtoFlow_buffer;
-
-/**
- * Frame destination.
- * Represents a peer as a destination for sending frames to.
- */
-typedef struct {
-    BReactor *reactor;
-    int frame_mtu;
-    PacketPassFairQueue queue;
-    PacketPassInactivityMonitor monitor;
-    PacketPassNotifier notifier;
-    DataProtoKeepaliveSource ka_source;
-    PacketRecvBlocker ka_blocker;
-    SinglePacketBuffer ka_buffer;
-    PacketPassFairQueueFlow ka_qflow;
-    BTimer receive_timer;
-    int up;
-    int up_report;
-    DataProtoSink_handler handler;
-    void *user;
-    BPending up_job;
-    struct DataProtoFlow_buffer *detaching_buffer;
-    DebugObject d_obj;
-    DebugCounter d_ctr;
-} DataProtoSink;
-
-/**
- * Receives frames from a {@link PacketRecvInterface} input and
- * allows the user to route them to buffers in {@link DataProtoFlow}'s.
- */
-typedef struct {
-    DataProtoSource_handler handler;
-    void *user;
-    BReactor *reactor;
-    int frame_mtu;
-    PacketRouter router;
-    uint8_t *current_buf;
-    int current_recv_len;
-    DebugObject d_obj;
-    DebugCounter d_ctr;
-} DataProtoSource;
-
-/**
- * Contains a buffer for frames from a specific peer to a specific peer.
- * Receives frames from a {@link DataProtoSource} as routed by the user.
- * Can be attached to a {@link DataProtoSink} to send out frames.
- */
-typedef struct {
-    DataProtoSource *source;
-    peerid_t source_id;
-    peerid_t dest_id;
-    DataProtoSink *sink_desired;
-    struct DataProtoFlow_buffer *b;
-    DebugObject d_obj;
-} DataProtoFlow;
-
-struct DataProtoFlow_buffer {
-    DataProtoFlow *flow;
-    int inactivity_time;
-    RouteBuffer rbuf;
-    PacketPassInactivityMonitor monitor;
-    PacketPassConnector connector;
-    DataProtoSink *sink;
-    PacketPassFairQueueFlow sink_qflow;
-};
-
-/**
- * Initializes the sink.
- * 
- * @param o the object
- * @param reactor reactor we live in
- * @param output output interface. Must support cancel functionality. Its MTU must be
- *               >=DATAPROTO_MAX_OVERHEAD.
- * @param keepalive_time keepalive time
- * @param tolerance_time after how long of not having received anything from the peer
- *                       to consider the link down
- * @param handler up state handler
- * @param user value to pass to handler
- * @return 1 on success, 0 on failure
- */
-int DataProtoSink_Init (DataProtoSink *o, BReactor *reactor, PacketPassInterface *output, btime_t keepalive_time, btime_t tolerance_time, DataProtoSink_handler handler, void *user) WARN_UNUSED;
-
-/**
- * Frees the sink.
- * There must be no local sources attached.
- * 
- * @param o the object
- */
-void DataProtoSink_Free (DataProtoSink *o);
-
-/**
- * Notifies the sink that a packet was received from the peer.
- * Must not be in freeing state.
- * 
- * @param o the object
- * @param peer_receiving whether the DATAPROTO_FLAGS_RECEIVING_KEEPALIVES flag was set in the packet.
- *                       Must be 0 or 1.
- */
-void DataProtoSink_Received (DataProtoSink *o, int peer_receiving);
-
-/**
- * Initiazes the source.
- * 
- * @param o the object
- * @param input frame input. Its input MTU must be <= INT_MAX - DATAPROTO_MAX_OVERHEAD.
- * @param handler handler called when a frame arrives to allow the user to route it to
- *                appropriate {@link DataProtoFlow}'s.
- * @param user value passed to handler
- * @param reactor reactor we live in
- * @return 1 on success, 0 on failure
- */
-int DataProtoSource_Init (DataProtoSource *o, PacketRecvInterface *input, DataProtoSource_handler handler, void *user, BReactor *reactor) WARN_UNUSED;
-
-/**
- * Frees the source.
- * There must be no {@link DataProtoFlow}'s using this source.
- * 
- * @param o the object
- */
-void DataProtoSource_Free (DataProtoSource *o);
-
-/**
- * Initializes the flow.
- * The flow is initialized in not attached state.
- * 
- * @param o the object
- * @param source source to receive frames from
- * @param source_id source peer ID to encode in the headers (i.e. our ID)
- * @param dest_id destination peer ID to encode in the headers (i.e. ID if the peer this
- *                flow belongs to)
- * @param num_packets number of packets the buffer should hold. Must be >0.
- * @param inactivity_time milliseconds of output inactivity after which to call the
- *                        inactivity handler; <0 to disable. Note that the flow is considered
- *                        active as long as its buffer is non-empty, even if is not attached to
- *                        a {@link DataProtoSink}.
- * @param user value to pass to handler
- * @param handler_inactivity inactivity handler, if inactivity_time >=0
- * @return 1 on success, 0 on failure
- */
-int DataProtoFlow_Init (DataProtoFlow *o, DataProtoSource *source, peerid_t source_id, peerid_t dest_id, int num_packets, int inactivity_time, void *user,
-                        DataProtoFlow_handler_inactivity handler_inactivity) WARN_UNUSED;
-
-/**
- * Frees the flow.
- * The flow must be in not attached state.
- * 
- * @param o the object
- */
-void DataProtoFlow_Free (DataProtoFlow *o);
-
-/**
- * Routes a frame from the flow's source to this flow.
- * Must be called from within the job context of the {@link DataProtoSource_handler} handler.
- * Must not be called after this has been called with more=0 for the current frame.
- * 
- * @param o the object
- * @param more whether the current frame may have to be routed to more
- *             flows. If 0, must not be called again until the handler is
- *             called for the next frame. Must be 0 or 1.
- */
-void DataProtoFlow_Route (DataProtoFlow *o, int more);
-
-/**
- * Attaches the flow to a sink.
- * The flow must be in not attached state.
- * 
- * @param o the object
- * @param sink sink to attach to. This flow's frame_mtu must be <=
- *             (output MTU of sink) - DATAPROTO_MAX_OVERHEAD.
- */
-void DataProtoFlow_Attach (DataProtoFlow *o, DataProtoSink *sink);
-
-/**
- * Detaches the flow from a destination.
- * The flow must be in attached state.
- * 
- * @param o the object
- */
-void DataProtoFlow_Detach (DataProtoFlow *o);
-
-#endif
diff --git a/external/badvpn_dns/client/DataProtoKeepaliveSource.c b/external/badvpn_dns/client/DataProtoKeepaliveSource.c
deleted file mode 100644
index 834c42f..0000000
--- a/external/badvpn_dns/client/DataProtoKeepaliveSource.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * @file DataProtoKeepaliveSource.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-
-#include <protocol/dataproto.h>
-#include <misc/byteorder.h>
-
-#include "DataProtoKeepaliveSource.h"
-
-static void output_handler_recv (DataProtoKeepaliveSource *o, uint8_t *data)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    struct dataproto_header header;
-    header.flags = htol8(0);
-    header.from_id = htol16(0);
-    header.num_peer_ids = htol16(0);
-    memcpy(data, &header, sizeof(header));
-    
-    // finish packet
-    PacketRecvInterface_Done(&o->output, sizeof(struct dataproto_header));
-}
-
-void DataProtoKeepaliveSource_Init (DataProtoKeepaliveSource *o, BPendingGroup *pg)
-{
-    // init output
-    PacketRecvInterface_Init(&o->output, sizeof(struct dataproto_header), (PacketRecvInterface_handler_recv)output_handler_recv, o, pg);
-    
-    DebugObject_Init(&o->d_obj);
-}
-
-void DataProtoKeepaliveSource_Free (DataProtoKeepaliveSource *o)
-{
-    DebugObject_Free(&o->d_obj);
-
-    // free output
-    PacketRecvInterface_Free(&o->output);
-}
-
-PacketRecvInterface * DataProtoKeepaliveSource_GetOutput (DataProtoKeepaliveSource *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->output;
-}
diff --git a/external/badvpn_dns/client/DataProtoKeepaliveSource.h b/external/badvpn_dns/client/DataProtoKeepaliveSource.h
deleted file mode 100644
index 4488e24..0000000
--- a/external/badvpn_dns/client/DataProtoKeepaliveSource.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * @file DataProtoKeepaliveSource.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * A {@link PacketRecvInterface} source which provides DataProto keepalive packets.
- */
-
-#ifndef BADVPN_DATAPROTOKEEPALIVESOURCE_H
-#define BADVPN_DATAPROTOKEEPALIVESOURCE_H
-
-#include <base/DebugObject.h>
-#include <flow/PacketRecvInterface.h>
-
-/**
- * A {@link PacketRecvInterface} source which provides DataProto keepalive packets.
- * These packets have no payload, no destination peers and flags zero.
- */
-typedef struct {
-    DebugObject d_obj;
-    PacketRecvInterface output;
-} DataProtoKeepaliveSource;
-
-/**
- * Initializes the object.
- *
- * @param o the object
- * @param pg pending group
- */
-void DataProtoKeepaliveSource_Init (DataProtoKeepaliveSource *o, BPendingGroup *pg);
-
-/**
- * Frees the object.
- *
- * @param o the object
- */
-void DataProtoKeepaliveSource_Free (DataProtoKeepaliveSource *o);
-
-/**
- * Returns the output interface.
- * The MTU of the output interface will be sizeof(struct dataproto_header).
- *
- * @param o the object
- * @return output interface
- */
-PacketRecvInterface * DataProtoKeepaliveSource_GetOutput (DataProtoKeepaliveSource *o);
-
-#endif
diff --git a/external/badvpn_dns/client/DatagramPeerIO.c b/external/badvpn_dns/client/DatagramPeerIO.c
deleted file mode 100644
index e3a8f68..0000000
--- a/external/badvpn_dns/client/DatagramPeerIO.c
+++ /dev/null
@@ -1,425 +0,0 @@
-/**
- * @file DatagramPeerIO.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <client/DatagramPeerIO.h>
-
-#include <generated/blog_channel_DatagramPeerIO.h>
-
-#define DATAGRAMPEERIO_MODE_NONE 0
-#define DATAGRAMPEERIO_MODE_CONNECT 1
-#define DATAGRAMPEERIO_MODE_BIND 2
-
-#define PeerLog(_o, ...) BLog_LogViaFunc((_o)->logfunc, (_o)->user, BLOG_CURRENT_CHANNEL, __VA_ARGS__)
-
-static void init_io (DatagramPeerIO *o);
-static void free_io (DatagramPeerIO *o);
-static void dgram_handler (DatagramPeerIO *o, int event);
-static void reset_mode (DatagramPeerIO *o);
-static void recv_decoder_notifier_handler (DatagramPeerIO *o, uint8_t *data, int data_len);
-
-void init_io (DatagramPeerIO *o)
-{
-    // init dgram recv interface
-    BDatagram_RecvAsync_Init(&o->dgram, o->effective_socket_mtu);
-    
-    // connect source
-    PacketRecvConnector_ConnectInput(&o->recv_connector, BDatagram_RecvAsync_GetIf(&o->dgram));
-    
-    // init dgram send interface
-    BDatagram_SendAsync_Init(&o->dgram, o->effective_socket_mtu);
-    
-    // connect sink
-    PacketPassConnector_ConnectOutput(&o->send_connector, BDatagram_SendAsync_GetIf(&o->dgram));
-}
-
-void free_io (DatagramPeerIO *o)
-{
-    // disconnect sink
-    PacketPassConnector_DisconnectOutput(&o->send_connector);
-    
-    // free dgram send interface
-    BDatagram_SendAsync_Free(&o->dgram);
-    
-    // disconnect source
-    PacketRecvConnector_DisconnectInput(&o->recv_connector);
-    
-    // free dgram recv interface
-    BDatagram_RecvAsync_Free(&o->dgram);
-}
-
-void dgram_handler (DatagramPeerIO *o, int event)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->mode == DATAGRAMPEERIO_MODE_CONNECT || o->mode == DATAGRAMPEERIO_MODE_BIND)
-    
-    PeerLog(o, BLOG_NOTICE, "error");
-    
-    // reset mode
-    reset_mode(o);
-    
-    // report error
-    if (o->handler_error) {
-        o->handler_error(o->user);
-        return;
-    }
-}
-
-void reset_mode (DatagramPeerIO *o)
-{
-    ASSERT(o->mode == DATAGRAMPEERIO_MODE_NONE || o->mode == DATAGRAMPEERIO_MODE_CONNECT || o->mode == DATAGRAMPEERIO_MODE_BIND)
-    
-    if (o->mode == DATAGRAMPEERIO_MODE_NONE) {
-        return;
-    }
-    
-    // remove recv notifier handler
-    PacketPassNotifier_SetHandler(&o->recv_notifier, NULL, NULL);
-    
-    // free I/O
-    free_io(o);
-    
-    // free datagram object
-    BDatagram_Free(&o->dgram);
-    
-    // set mode
-    o->mode = DATAGRAMPEERIO_MODE_NONE;
-}
-
-void recv_decoder_notifier_handler (DatagramPeerIO *o, uint8_t *data, int data_len)
-{
-    ASSERT(o->mode == DATAGRAMPEERIO_MODE_BIND)
-    DebugObject_Access(&o->d_obj);
-    
-    // obtain addresses from last received packet
-    BAddr addr;
-    BIPAddr local_addr;
-    ASSERT_EXECUTE(BDatagram_GetLastReceiveAddrs(&o->dgram, &addr, &local_addr))
-    
-    // check address family just in case
-    if (!BDatagram_AddressFamilySupported(addr.type)) {
-        PeerLog(o, BLOG_ERROR, "unsupported receive address");
-        return;
-    }
-    
-    // update addresses
-    BDatagram_SetSendAddrs(&o->dgram, addr, local_addr);
-}
-
-int DatagramPeerIO_Init (
-    DatagramPeerIO *o,
-    BReactor *reactor,
-    int payload_mtu,
-    int socket_mtu,
-    struct spproto_security_params sp_params,
-    btime_t latency,
-    int num_frames,
-    PacketPassInterface *recv_userif,
-    int otp_warning_count,
-    BThreadWorkDispatcher *twd,
-    void *user,
-    BLog_logfunc logfunc,
-    DatagramPeerIO_handler_error handler_error,
-    DatagramPeerIO_handler_otp_warning handler_otp_warning,
-    DatagramPeerIO_handler_otp_ready handler_otp_ready
-)
-{
-    ASSERT(payload_mtu >= 0)
-    ASSERT(socket_mtu >= 0)
-    spproto_assert_security_params(sp_params);
-    ASSERT(num_frames > 0)
-    ASSERT(PacketPassInterface_GetMTU(recv_userif) >= payload_mtu)
-    if (SPPROTO_HAVE_OTP(sp_params)) {
-        ASSERT(otp_warning_count > 0)
-        ASSERT(otp_warning_count <= sp_params.otp_num)
-    }
-    
-    // set parameters
-    o->reactor = reactor;
-    o->payload_mtu = payload_mtu;
-    o->sp_params = sp_params;
-    o->user = user;
-    o->logfunc = logfunc;
-    o->handler_error = handler_error;
-    
-    // check num frames (for FragmentProtoAssembler)
-    if (num_frames >= FPA_MAX_TIME) {
-        PeerLog(o, BLOG_ERROR, "num_frames is too big");
-        goto fail0;
-    }
-    
-    // check payload MTU (for FragmentProto)
-    if (o->payload_mtu > UINT16_MAX) {
-        PeerLog(o, BLOG_ERROR, "payload MTU is too big");
-        goto fail0;
-    }
-    
-    // calculate SPProto payload MTU
-    if ((o->spproto_payload_mtu = spproto_payload_mtu_for_carrier_mtu(o->sp_params, socket_mtu)) <= (int)sizeof(struct fragmentproto_chunk_header)) {
-        PeerLog(o, BLOG_ERROR, "socket MTU is too small");
-        goto fail0;
-    }
-    
-    // calculate effective socket MTU
-    if ((o->effective_socket_mtu = spproto_carrier_mtu_for_payload_mtu(o->sp_params, o->spproto_payload_mtu)) < 0) {
-        PeerLog(o, BLOG_ERROR, "spproto_carrier_mtu_for_payload_mtu failed !?");
-        goto fail0;
-    }
-    
-    // init receiving
-    
-    // init assembler
-    if (!FragmentProtoAssembler_Init(&o->recv_assembler, o->spproto_payload_mtu, recv_userif, num_frames, fragmentproto_max_chunks_for_frame(o->spproto_payload_mtu, o->payload_mtu),
-                                     BReactor_PendingGroup(o->reactor), o->user, o->logfunc
-    )) {
-        PeerLog(o, BLOG_ERROR, "FragmentProtoAssembler_Init failed");
-        goto fail0;
-    }
-    
-    // init notifier
-    PacketPassNotifier_Init(&o->recv_notifier, FragmentProtoAssembler_GetInput(&o->recv_assembler), BReactor_PendingGroup(o->reactor));
-    
-    // init decoder
-    if (!SPProtoDecoder_Init(&o->recv_decoder, PacketPassNotifier_GetInput(&o->recv_notifier), o->sp_params, 2, BReactor_PendingGroup(o->reactor), twd, o->user, o->logfunc)) {
-        PeerLog(o, BLOG_ERROR, "SPProtoDecoder_Init failed");
-        goto fail1;
-    }
-    SPProtoDecoder_SetHandlers(&o->recv_decoder, handler_otp_ready, user);
-    
-    // init connector
-    PacketRecvConnector_Init(&o->recv_connector, o->effective_socket_mtu, BReactor_PendingGroup(o->reactor));
-    
-    // init buffer
-    if (!SinglePacketBuffer_Init(&o->recv_buffer, PacketRecvConnector_GetOutput(&o->recv_connector), SPProtoDecoder_GetInput(&o->recv_decoder), BReactor_PendingGroup(o->reactor))) {
-        PeerLog(o, BLOG_ERROR, "SinglePacketBuffer_Init failed");
-        goto fail2;
-    }
-    
-    // init sending base
-    
-    // init disassembler
-    FragmentProtoDisassembler_Init(&o->send_disassembler, o->reactor, o->payload_mtu, o->spproto_payload_mtu, -1, latency);
-    
-    // init encoder
-    if (!SPProtoEncoder_Init(&o->send_encoder, FragmentProtoDisassembler_GetOutput(&o->send_disassembler), o->sp_params, otp_warning_count, BReactor_PendingGroup(o->reactor), twd)) {
-        PeerLog(o, BLOG_ERROR, "SPProtoEncoder_Init failed");
-        goto fail3;
-    }
-    SPProtoEncoder_SetHandlers(&o->send_encoder, handler_otp_warning, user);
-    
-    // init connector
-    PacketPassConnector_Init(&o->send_connector, o->effective_socket_mtu, BReactor_PendingGroup(o->reactor));
-    
-    // init buffer
-    if (!SinglePacketBuffer_Init(&o->send_buffer, SPProtoEncoder_GetOutput(&o->send_encoder), PacketPassConnector_GetInput(&o->send_connector), BReactor_PendingGroup(o->reactor))) {
-        PeerLog(o, BLOG_ERROR, "SinglePacketBuffer_Init failed");
-        goto fail4;
-    }
-    
-    // set mode
-    o->mode = DATAGRAMPEERIO_MODE_NONE;
-    
-    DebugObject_Init(&o->d_obj);
-    return 1;
-    
-fail4:
-    PacketPassConnector_Free(&o->send_connector);
-    SPProtoEncoder_Free(&o->send_encoder);
-fail3:
-    FragmentProtoDisassembler_Free(&o->send_disassembler);
-    SinglePacketBuffer_Free(&o->recv_buffer);
-fail2:
-    PacketRecvConnector_Free(&o->recv_connector);
-    SPProtoDecoder_Free(&o->recv_decoder);
-fail1:
-    PacketPassNotifier_Free(&o->recv_notifier);
-    FragmentProtoAssembler_Free(&o->recv_assembler);
-fail0:
-    return 0;
-}
-
-void DatagramPeerIO_Free (DatagramPeerIO *o)
-{
-    DebugObject_Free(&o->d_obj);
-
-    // reset mode
-    reset_mode(o);
-    
-    // free sending base
-    SinglePacketBuffer_Free(&o->send_buffer);
-    PacketPassConnector_Free(&o->send_connector);
-    SPProtoEncoder_Free(&o->send_encoder);
-    FragmentProtoDisassembler_Free(&o->send_disassembler);
-    
-    // free receiving
-    SinglePacketBuffer_Free(&o->recv_buffer);
-    PacketRecvConnector_Free(&o->recv_connector);
-    SPProtoDecoder_Free(&o->recv_decoder);
-    PacketPassNotifier_Free(&o->recv_notifier);
-    FragmentProtoAssembler_Free(&o->recv_assembler);
-}
-
-PacketPassInterface * DatagramPeerIO_GetSendInput (DatagramPeerIO *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return FragmentProtoDisassembler_GetInput(&o->send_disassembler);
-}
-
-int DatagramPeerIO_Connect (DatagramPeerIO *o, BAddr addr)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    // reset mode
-    reset_mode(o);
-    
-    // check address
-    if (!BDatagram_AddressFamilySupported(addr.type)) {
-        PeerLog(o, BLOG_ERROR, "BDatagram_AddressFamilySupported failed");
-        goto fail0;
-    }
-    
-    // init dgram
-    if (!BDatagram_Init(&o->dgram, addr.type, o->reactor, o, (BDatagram_handler)dgram_handler)) {
-        PeerLog(o, BLOG_ERROR, "BDatagram_Init failed");
-        goto fail0;
-    }
-    
-    // set send address
-    BIPAddr local_addr;
-    BIPAddr_InitInvalid(&local_addr);
-    BDatagram_SetSendAddrs(&o->dgram, addr, local_addr);
-    
-    // init I/O
-    init_io(o);
-    
-    // set mode
-    o->mode = DATAGRAMPEERIO_MODE_CONNECT;
-    
-    return 1;
-    
-fail0:
-    return 0;
-}
-
-int DatagramPeerIO_Bind (DatagramPeerIO *o, BAddr addr)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(BDatagram_AddressFamilySupported(addr.type))
-    
-    // reset mode
-    reset_mode(o);
-    
-    // init dgram
-    if (!BDatagram_Init(&o->dgram, addr.type, o->reactor, o, (BDatagram_handler)dgram_handler)) {
-        PeerLog(o, BLOG_ERROR, "BDatagram_Init failed");
-        goto fail0;
-    }
-    
-    // bind dgram
-    if (!BDatagram_Bind(&o->dgram, addr)) {
-        PeerLog(o, BLOG_INFO, "BDatagram_Bind failed");
-        goto fail1;
-    }
-    
-    // init I/O
-    init_io(o);
-    
-    // set recv notifier handler
-    PacketPassNotifier_SetHandler(&o->recv_notifier, (PacketPassNotifier_handler_notify)recv_decoder_notifier_handler, o);
-    
-    // set mode
-    o->mode = DATAGRAMPEERIO_MODE_BIND;
-    
-    return 1;
-    
-fail1:
-    BDatagram_Free(&o->dgram);
-fail0:
-    return 0;
-}
-
-void DatagramPeerIO_SetEncryptionKey (DatagramPeerIO *o, uint8_t *encryption_key)
-{
-    ASSERT(SPPROTO_HAVE_ENCRYPTION(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    // set sending key
-    SPProtoEncoder_SetEncryptionKey(&o->send_encoder, encryption_key);
-    
-    // set receiving key
-    SPProtoDecoder_SetEncryptionKey(&o->recv_decoder, encryption_key);
-}
-
-void DatagramPeerIO_RemoveEncryptionKey (DatagramPeerIO *o)
-{
-    ASSERT(SPPROTO_HAVE_ENCRYPTION(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    // remove sending key
-    SPProtoEncoder_RemoveEncryptionKey(&o->send_encoder);
-    
-    // remove receiving key
-    SPProtoDecoder_RemoveEncryptionKey(&o->recv_decoder);
-}
-
-void DatagramPeerIO_SetOTPSendSeed (DatagramPeerIO *o, uint16_t seed_id, uint8_t *key, uint8_t *iv)
-{
-    ASSERT(SPPROTO_HAVE_OTP(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    // set sending seed
-    SPProtoEncoder_SetOTPSeed(&o->send_encoder, seed_id, key, iv);
-}
-
-void DatagramPeerIO_RemoveOTPSendSeed (DatagramPeerIO *o)
-{
-    ASSERT(SPPROTO_HAVE_OTP(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    // remove sending seed
-    SPProtoEncoder_RemoveOTPSeed(&o->send_encoder);
-}
-
-void DatagramPeerIO_AddOTPRecvSeed (DatagramPeerIO *o, uint16_t seed_id, uint8_t *key, uint8_t *iv)
-{
-    ASSERT(SPPROTO_HAVE_OTP(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    // add receiving seed
-    SPProtoDecoder_AddOTPSeed(&o->recv_decoder, seed_id, key, iv);
-}
-
-void DatagramPeerIO_RemoveOTPRecvSeeds (DatagramPeerIO *o)
-{
-    ASSERT(SPPROTO_HAVE_OTP(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    // remove receiving seeds
-    SPProtoDecoder_RemoveOTPSeeds(&o->recv_decoder);
-}
diff --git a/external/badvpn_dns/client/DatagramPeerIO.h b/external/badvpn_dns/client/DatagramPeerIO.h
deleted file mode 100644
index 5d19b5a..0000000
--- a/external/badvpn_dns/client/DatagramPeerIO.h
+++ /dev/null
@@ -1,271 +0,0 @@
-/**
- * @file DatagramPeerIO.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Object for comminicating with a peer using a datagram socket.
- */
-
-#ifndef BADVPN_CLIENT_DATAGRAMPEERIO_H
-#define BADVPN_CLIENT_DATAGRAMPEERIO_H
-
-#include <stdint.h>
-
-#include <misc/debug.h>
-#include <protocol/spproto.h>
-#include <protocol/fragmentproto.h>
-#include <base/DebugObject.h>
-#include <base/BLog.h>
-#include <system/BReactor.h>
-#include <system/BAddr.h>
-#include <system/BDatagram.h>
-#include <system/BTime.h>
-#include <flow/PacketPassInterface.h>
-#include <flow/PacketPassConnector.h>
-#include <flow/SinglePacketBuffer.h>
-#include <flow/PacketRecvConnector.h>
-#include <flow/PacketPassNotifier.h>
-#include <client/FragmentProtoDisassembler.h>
-#include <client/FragmentProtoAssembler.h>
-#include <client/SPProtoEncoder.h>
-#include <client/SPProtoDecoder.h>
-
-/**
- * Callback function invoked when an error occurs with the peer connection.
- * The object has entered default state.
- * May be called from within a sending Send call.
- *
- * @param user as in {@link DatagramPeerIO_SetHandlers}
- */
-typedef void (*DatagramPeerIO_handler_error) (void *user);
-
-/**
- * Handler function invoked when the number of used OTPs has reached
- * the specified warning number in {@link DatagramPeerIO_SetOTPWarningHandler}.
- * May be called from within a sending Send call.
- *
- * @param user as in {@link DatagramPeerIO_SetHandlers}
- */
-typedef void (*DatagramPeerIO_handler_otp_warning) (void *user);
-
-/**
- * Handler called when OTP generation for a new receive seed is finished.
- * 
- * @param user as in {@link DatagramPeerIO_SetHandlers}
- */
-typedef void (*DatagramPeerIO_handler_otp_ready) (void *user);
-
-/**
- * Object for comminicating with a peer using a datagram socket.
- *
- * The user provides data for sending to the peer through {@link PacketPassInterface}.
- * Received data is provided to the user through {@link PacketPassInterface}.
- *
- * The object has a logical state called a mode, which is one of the following:
- *     - default - nothing is send or received
- *     - connecting - an address was provided by the user for sending datagrams to.
- *                    Datagrams are being sent to that address through a socket,
- *                    and datagrams are being received on the same socket.
- *     - binding - an address was provided by the user to bind a socket to.
- *                 Datagrams are being received on the socket. Datagrams are not being
- *                 sent initially. When a datagram is received, its source address is
- *                 used as a destination address for sending datagrams.
- */
-typedef struct {
-    DebugObject d_obj;
-    BReactor *reactor;
-    int payload_mtu;
-    struct spproto_security_params sp_params;
-    void *user;
-    BLog_logfunc logfunc;
-    DatagramPeerIO_handler_error handler_error;
-    int spproto_payload_mtu;
-    int effective_socket_mtu;
-    
-    // sending base
-    FragmentProtoDisassembler send_disassembler;
-    SPProtoEncoder send_encoder;
-    SinglePacketBuffer send_buffer;
-    PacketPassConnector send_connector;
-    
-    // receiving
-    PacketRecvConnector recv_connector;
-    SinglePacketBuffer recv_buffer;
-    SPProtoDecoder recv_decoder;
-    PacketPassNotifier recv_notifier;
-    FragmentProtoAssembler recv_assembler;
-    
-    // mode
-    int mode;
-    
-    // datagram object
-    BDatagram dgram;
-} DatagramPeerIO;
-
-/**
- * Initializes the object.
- * The interface is initialized in default mode.
- * {@link BLog_Init} must have been done.
- * {@link BNetwork_GlobalInit} must have been done.
- * {@link BSecurity_GlobalInitThreadSafe} must have been done if
- * {@link BThreadWorkDispatcher_UsingThreads}(twd) = 1.
- *
- * @param o the object
- * @param reactor {@link BReactor} we live in
- * @param payload_mtu maximum payload size. Must be >=0.
- * @param socket_mtu maximum datagram size for the socket. Must be >=0. Must be large enough so it is possible to
- *                   send a FragmentProto chunk with one byte of data over SPProto, i.e. the following has to hold:
- *                   spproto_payload_mtu_for_carrier_mtu(sp_params, socket_mtu) > sizeof(struct fragmentproto_chunk_header)
- * @param sp_params SPProto security parameters
- * @param latency latency parameter to {@link FragmentProtoDisassembler_Init}.
- * @param num_frames num_frames parameter to {@link FragmentProtoAssembler_Init}. Must be >0.
- * @param recv_userif interface to pass received packets to the user. Its MTU must be >=payload_mtu.
- * @param otp_warning_count If using OTPs, after how many encoded packets to call the handler.
- *                          In this case, must be >0 and <=sp_params.otp_num.
- * @param twd thread work dispatcher
- * @param user value to pass to handlers
- * @param logfunc function which prepends the log prefix using {@link BLog_Append}
- * @param handler_error error handler
- * @param handler_otp_warning OTP warning handler
- * @param handler_otp_ready handler called when OTP generation for a new receive seed is finished
- * @return 1 on success, 0 on failure
- */
-int DatagramPeerIO_Init (
-    DatagramPeerIO *o,
-    BReactor *reactor,
-    int payload_mtu,
-    int socket_mtu,
-    struct spproto_security_params sp_params,
-    btime_t latency,
-    int num_frames,
-    PacketPassInterface *recv_userif,
-    int otp_warning_count,
-    BThreadWorkDispatcher *twd,
-    void *user,
-    BLog_logfunc logfunc,
-    DatagramPeerIO_handler_error handler_error,
-    DatagramPeerIO_handler_otp_warning handler_otp_warning,
-    DatagramPeerIO_handler_otp_ready handler_otp_ready
-) WARN_UNUSED;
-
-/**
- * Frees the object.
- *
- * @param o the object
- */
-void DatagramPeerIO_Free (DatagramPeerIO *o);
-
-/**
- * Returns an interface the user should use to send packets.
- * The OTP warning handler may be called from within Send calls
- * to the interface.
- *
- * @param o the object
- * @return sending interface
- */
-PacketPassInterface * DatagramPeerIO_GetSendInput (DatagramPeerIO *o);
-
-/**
- * Attempts to establish connection to the peer which has bound to an address.
- * On success, the interface enters connecting mode.
- * On failure, the interface enters default mode.
- *
- * @param o the object
- * @param addr address to send packets to
- * @return 1 on success, 0 on failure
- */
-int DatagramPeerIO_Connect (DatagramPeerIO *o, BAddr addr) WARN_UNUSED;
-
-/**
- * Attempts to establish connection to the peer by binding to an address.
- * On success, the interface enters connecting mode.
- * On failure, the interface enters default mode.
- *
- * @param o the object
- * @param addr address to bind to. Must be supported according to
- *             {@link BDatagram_AddressFamilySupported}.
- * @return 1 on success, 0 on failure
- */
-int DatagramPeerIO_Bind (DatagramPeerIO *o, BAddr addr) WARN_UNUSED;
-
-/**
- * Sets the encryption key to use for sending and receiving.
- * Encryption must be enabled.
- *
- * @param o the object
- * @param encryption_key key to use
- */
-void DatagramPeerIO_SetEncryptionKey (DatagramPeerIO *o, uint8_t *encryption_key);
-
-/**
- * Removed the encryption key to use for sending and receiving.
- * Encryption must be enabled.
- *
- * @param o the object
- */
-void DatagramPeerIO_RemoveEncryptionKey (DatagramPeerIO *o);
-
-/**
- * Sets the OTP seed for sending.
- * OTPs must be enabled.
- *
- * @param o the object
- * @param seed_id seed identifier
- * @param key OTP encryption key
- * @param iv OTP initialization vector
- */
-void DatagramPeerIO_SetOTPSendSeed (DatagramPeerIO *o, uint16_t seed_id, uint8_t *key, uint8_t *iv);
-
-/**
- * Removes the OTP seed for sending of one is configured.
- * OTPs must be enabled.
- *
- * @param o the object
- */
-void DatagramPeerIO_RemoveOTPSendSeed (DatagramPeerIO *o);
-
-/**
- * Adds an OTP seed for reciving.
- * OTPs must be enabled.
- *
- * @param o the object
- * @param seed_id seed identifier
- * @param key OTP encryption key
- * @param iv OTP initialization vector
- */
-void DatagramPeerIO_AddOTPRecvSeed (DatagramPeerIO *o, uint16_t seed_id, uint8_t *key, uint8_t *iv);
-
-/**
- * Removes all OTP seeds for reciving.
- * OTPs must be enabled.
- *
- * @param o the object
- */
-void DatagramPeerIO_RemoveOTPRecvSeeds (DatagramPeerIO *o);
-
-#endif
diff --git a/external/badvpn_dns/client/FragmentProtoAssembler.c b/external/badvpn_dns/client/FragmentProtoAssembler.c
deleted file mode 100644
index 8588c2e..0000000
--- a/external/badvpn_dns/client/FragmentProtoAssembler.c
+++ /dev/null
@@ -1,469 +0,0 @@
-/**
- * @file FragmentProtoAssembler.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <misc/offset.h>
-#include <misc/byteorder.h>
-#include <misc/balloc.h>
-
-#include "FragmentProtoAssembler.h"
-
-#include <generated/blog_channel_FragmentProtoAssembler.h>
-
-#define PeerLog(_o, ...) BLog_LogViaFunc((_o)->logfunc, (_o)->user, BLOG_CURRENT_CHANNEL, __VA_ARGS__)
-
-#include "FragmentProtoAssembler_tree.h"
-#include <structure/SAvl_impl.h>
-
-static void free_frame (FragmentProtoAssembler *o, struct FragmentProtoAssembler_frame *frame)
-{
-    // remove from used list
-    LinkedList1_Remove(&o->frames_used, &frame->list_node);
-    // remove from used tree
-    FPAFramesTree_Remove(&o->frames_used_tree, 0, frame);
-    
-    // append to free list
-    LinkedList1_Append(&o->frames_free, &frame->list_node);
-}
-
-static void free_oldest_frame (FragmentProtoAssembler *o)
-{
-    ASSERT(!LinkedList1_IsEmpty(&o->frames_used))
-    
-    // obtain oldest frame (first on the list)
-    LinkedList1Node *list_node = LinkedList1_GetFirst(&o->frames_used);
-    ASSERT(list_node)
-    struct FragmentProtoAssembler_frame *frame = UPPER_OBJECT(list_node, struct FragmentProtoAssembler_frame, list_node);
-    
-    // free frame
-    free_frame(o, frame);
-}
-
-static struct FragmentProtoAssembler_frame * allocate_new_frame (FragmentProtoAssembler *o, fragmentproto_frameid id)
-{
-    ASSERT(!FPAFramesTree_LookupExact(&o->frames_used_tree, 0, id))
-    
-    // if there are no free entries, free the oldest used one
-    if (LinkedList1_IsEmpty(&o->frames_free)) {
-        PeerLog(o, BLOG_INFO, "freeing used frame");
-        free_oldest_frame(o);
-    }
-    
-    // obtain frame entry
-    LinkedList1Node *list_node = LinkedList1_GetFirst(&o->frames_free);
-    ASSERT(list_node)
-    struct FragmentProtoAssembler_frame *frame = UPPER_OBJECT(list_node, struct FragmentProtoAssembler_frame, list_node);
-    
-    // remove from free list
-    LinkedList1_Remove(&o->frames_free, &frame->list_node);
-    
-    // initialize values
-    frame->id = id;
-    frame->time = o->time;
-    frame->num_chunks = 0;
-    frame->sum = 0;
-    frame->length = -1;
-    frame->length_so_far = 0;
-    
-    // append to used list
-    LinkedList1_Append(&o->frames_used, &frame->list_node);
-    // insert to used tree
-    int res = FPAFramesTree_Insert(&o->frames_used_tree, 0, frame, NULL);
-    ASSERT_EXECUTE(res)
-    
-    return frame;
-}
-
-static int chunks_overlap (int c1_start, int c1_len, int c2_start, int c2_len)
-{
-    return (c1_start + c1_len > c2_start && c2_start + c2_len > c1_start);
-}
-
-static int frame_is_timed_out (FragmentProtoAssembler *o, struct FragmentProtoAssembler_frame *frame)
-{
-    ASSERT(frame->time <= o->time)
-    
-    return (o->time - frame->time > o->time_tolerance);
-}
-
-static void reduce_times (FragmentProtoAssembler *o)
-{
-    // find the frame with minimal time, removing timed out frames
-    struct FragmentProtoAssembler_frame *minframe = NULL;
-    LinkedList1Node *list_node = LinkedList1_GetFirst(&o->frames_used);
-    while (list_node) {
-        LinkedList1Node *next = LinkedList1Node_Next(list_node);
-        struct FragmentProtoAssembler_frame *frame = UPPER_OBJECT(list_node, struct FragmentProtoAssembler_frame, list_node);
-        if (frame_is_timed_out(o, frame)) {
-            PeerLog(o, BLOG_INFO, "freeing timed out frame (while reducing times)");
-            free_frame(o, frame);
-        } else {
-            if (!minframe || frame->time < minframe->time) {
-                minframe = frame;
-            }
-        }
-        list_node = next;
-    }
-    
-    if (!minframe) {
-        // have no frames, set packet time to zero
-        o->time = 0;
-        return;
-    }
-    
-    uint32_t min_time = minframe->time;
-    
-    // subtract minimal time from all frames
-    for (list_node = LinkedList1_GetFirst(&o->frames_used); list_node; list_node = LinkedList1Node_Next(list_node)) {
-        struct FragmentProtoAssembler_frame *frame = UPPER_OBJECT(list_node, struct FragmentProtoAssembler_frame, list_node);
-        frame->time -= min_time;
-    }
-    
-    // subtract minimal time from packet time
-    o->time -= min_time;
-}
-
-static int process_chunk (FragmentProtoAssembler *o, fragmentproto_frameid frame_id, int chunk_start, int chunk_len, int is_last, uint8_t *payload)
-{
-    ASSERT(chunk_start >= 0)
-    ASSERT(chunk_len >= 0)
-    ASSERT(is_last == 0 || is_last == 1)
-    
-    // verify chunk
-    
-    // check start
-    if (chunk_start > o->output_mtu) {
-        PeerLog(o, BLOG_INFO, "chunk starts outside");
-        return 0;
-    }
-    
-    // check frame size bound
-    if (chunk_len > o->output_mtu - chunk_start) {
-        PeerLog(o, BLOG_INFO, "chunk ends outside");
-        return 0;
-    }
-    
-    // calculate end
-    int chunk_end = chunk_start + chunk_len;
-    ASSERT(chunk_end >= 0)
-    ASSERT(chunk_end <= o->output_mtu)
-    
-    // lookup frame
-    struct FragmentProtoAssembler_frame *frame = FPAFramesTree_LookupExact(&o->frames_used_tree, 0, frame_id);
-    if (!frame) {
-        // frame not found, add a new one
-        frame = allocate_new_frame(o, frame_id);
-    } else {
-        // have existing frame with that ID
-        // check frame time
-        if (frame_is_timed_out(o, frame)) {
-            // frame is timed out, remove it and use a new one
-            PeerLog(o, BLOG_INFO, "freeing timed out frame (while processing chunk)");
-            free_frame(o, frame);
-            frame = allocate_new_frame(o, frame_id);
-        }
-    }
-    
-    ASSERT(frame->num_chunks < o->num_chunks)
-    
-    // check if the chunk overlaps with any existing chunks
-    for (int i = 0; i < frame->num_chunks; i++) {
-        struct FragmentProtoAssembler_chunk *chunk = &frame->chunks[i];
-        if (chunks_overlap(chunk->start, chunk->len, chunk_start, chunk_len)) {
-            PeerLog(o, BLOG_INFO, "chunk overlaps with existing chunk");
-            goto fail_frame;
-        }
-    }
-    
-    if (is_last) {
-        // this chunk is marked as last
-        if (frame->length >= 0) {
-            PeerLog(o, BLOG_INFO, "got last chunk, but already have one");
-            goto fail_frame;
-        }
-        // check if frame size according to this packet is consistent
-        // with existing chunks
-        if (frame->length_so_far > chunk_end) {
-            PeerLog(o, BLOG_INFO, "got last chunk, but already have data over its bound");
-            goto fail_frame;
-        }
-    } else {
-        // if we have length, chunk must be in its bound
-        if (frame->length >= 0) {
-            if (chunk_end > frame->length) {
-                PeerLog(o, BLOG_INFO, "chunk out of length bound");
-                goto fail_frame;
-            }
-        }
-    }
-    
-    // chunk is good, add it
-    
-    // update frame time
-    frame->time = o->time;
-    
-    // add chunk entry
-    struct FragmentProtoAssembler_chunk *chunk = &frame->chunks[frame->num_chunks];
-    chunk->start = chunk_start;
-    chunk->len = chunk_len;
-    frame->num_chunks++;
-    
-    // update sum
-    frame->sum += chunk_len;
-    
-    // update length
-    if (is_last) {
-        frame->length = chunk_end;
-    } else {
-        if (frame->length < 0) {
-            if (frame->length_so_far < chunk_end) {
-                frame->length_so_far = chunk_end;
-            }
-        }
-    }
-    
-    // copy chunk payload to buffer
-    memcpy(frame->buffer + chunk_start, payload, chunk_len);
-    
-    // is frame incomplete?
-    if (frame->length < 0 || frame->sum < frame->length) {
-        // if all chunks are used, fail it
-        if (frame->num_chunks == o->num_chunks) {
-            PeerLog(o, BLOG_INFO, "all chunks used, but frame not complete");
-            goto fail_frame;
-        }
-        
-        // wait for more chunks
-        return 0;
-    }
-    
-    ASSERT(frame->sum == frame->length)
-    
-    PeerLog(o, BLOG_DEBUG, "frame complete");
-    
-    // free frame entry
-    free_frame(o, frame);
-    
-    // send frame
-    PacketPassInterface_Sender_Send(o->output, frame->buffer, frame->length);
-    
-    return 1;
-    
-fail_frame:
-    free_frame(o, frame);
-    return 0;
-}
-
-static void process_input (FragmentProtoAssembler *o)
-{
-    ASSERT(o->in_len >= 0)
-    
-    // read chunks
-    while (o->in_pos < o->in_len) {
-        // obtain header
-        if (o->in_len - o->in_pos < sizeof(struct fragmentproto_chunk_header)) {
-            PeerLog(o, BLOG_INFO, "too little data for chunk header");
-            break;
-        }
-        struct fragmentproto_chunk_header header;
-        memcpy(&header, o->in + o->in_pos, sizeof(header));
-        o->in_pos += sizeof(struct fragmentproto_chunk_header);
-        fragmentproto_frameid frame_id = ltoh16(header.frame_id);
-        int chunk_start = ltoh16(header.chunk_start);
-        int chunk_len = ltoh16(header.chunk_len);
-        int is_last = ltoh8(header.is_last);
-        
-        // check is_last field
-        if (!(is_last == 0 || is_last == 1)) {
-            PeerLog(o, BLOG_INFO, "chunk is_last wrong");
-            break;
-        }
-        
-        // obtain data
-        if (o->in_len - o->in_pos < chunk_len) {
-            PeerLog(o, BLOG_INFO, "too little data for chunk data");
-            break;
-        }
-        
-        // process chunk
-        int res = process_chunk(o, frame_id, chunk_start, chunk_len, is_last, o->in + o->in_pos);
-        o->in_pos += chunk_len;
-        
-        if (res) {
-            // sending complete frame, stop processing input
-            return;
-        }
-    }
-    
-    // increment packet time
-    if (o->time == FPA_MAX_TIME) {
-        reduce_times(o);
-        if (!LinkedList1_IsEmpty(&o->frames_used)) {
-            ASSERT(o->time < FPA_MAX_TIME) // If there was a frame with zero time, it was removed because
-                                           // time_tolerance < FPA_MAX_TIME. So something >0 was subtracted.
-            o->time++;
-        } else {
-            // it was set to zero by reduce_times
-            ASSERT(o->time == 0)
-        }
-    } else {
-        o->time++;
-    }
-    
-    // set no input packet
-    o->in_len = -1;
-    
-    // finish input
-    PacketPassInterface_Done(&o->input);
-}
-
-static void input_handler_send (FragmentProtoAssembler *o, uint8_t *data, int data_len)
-{
-    ASSERT(data_len >= 0)
-    ASSERT(o->in_len == -1)
-    DebugObject_Access(&o->d_obj);
-    
-    // save input packet
-    o->in_len = data_len;
-    o->in = data;
-    o->in_pos = 0;
-    
-    process_input(o);
-}
-
-static void output_handler_done (FragmentProtoAssembler *o)
-{
-    ASSERT(o->in_len >= 0)
-    DebugObject_Access(&o->d_obj);
-    
-    process_input(o);
-}
-
-int FragmentProtoAssembler_Init (FragmentProtoAssembler *o, int input_mtu, PacketPassInterface *output, int num_frames, int num_chunks, BPendingGroup *pg, void *user, BLog_logfunc logfunc)
-{
-    ASSERT(input_mtu >= 0)
-    ASSERT(num_frames > 0)
-    ASSERT(num_frames < FPA_MAX_TIME) // needed so we can always subtract times when packet time is maximum
-    ASSERT(num_chunks > 0)
-    
-    // init arguments
-    o->output = output;
-    o->num_chunks = num_chunks;
-    o->user = user;
-    o->logfunc = logfunc;
-    
-    // init input
-    PacketPassInterface_Init(&o->input, input_mtu, (PacketPassInterface_handler_send)input_handler_send, o, pg);
-    
-    // init output
-    PacketPassInterface_Sender_Init(o->output, (PacketPassInterface_handler_done)output_handler_done, o);
-    
-    // remebmer output MTU
-    o->output_mtu = PacketPassInterface_GetMTU(o->output);
-    
-    // set packet time to zero
-    o->time = 0;
-    
-    // set time tolerance to num_frames
-    o->time_tolerance = num_frames;
-    
-    // allocate frames
-    if (!(o->frames_entries = (struct FragmentProtoAssembler_frame *)BAllocArray(num_frames, sizeof(o->frames_entries[0])))) {
-        goto fail1;
-    }
-    
-    // allocate chunks
-    if (!(o->frames_chunks = (struct FragmentProtoAssembler_chunk *)BAllocArray2(num_frames, o->num_chunks, sizeof(o->frames_chunks[0])))) {
-        goto fail2;
-    }
-    
-    // allocate buffers
-    if (!(o->frames_buffer = (uint8_t *)BAllocArray(num_frames, o->output_mtu))) {
-        goto fail3;
-    }
-    
-    // init frame lists
-    LinkedList1_Init(&o->frames_free);
-    LinkedList1_Init(&o->frames_used);
-    
-    // initialize frame entries
-    for (int i = 0; i < num_frames; i++) {
-        struct FragmentProtoAssembler_frame *frame = &o->frames_entries[i];
-        // set chunks array pointer
-        frame->chunks = o->frames_chunks + (size_t)i * o->num_chunks;
-        // set buffer pointer
-        frame->buffer = o->frames_buffer + (size_t)i * o->output_mtu;
-        // add to free list
-        LinkedList1_Append(&o->frames_free, &frame->list_node);
-    }
-    
-    // init tree
-    FPAFramesTree_Init(&o->frames_used_tree);
-    
-    // have no input packet
-    o->in_len = -1;
-    
-    DebugObject_Init(&o->d_obj);
-    
-    return 1;
-    
-fail3:
-    BFree(o->frames_chunks);
-fail2:
-    BFree(o->frames_entries);
-fail1:
-    PacketPassInterface_Free(&o->input);
-    return 0;
-}
-
-void FragmentProtoAssembler_Free (FragmentProtoAssembler *o)
-{
-    DebugObject_Free(&o->d_obj);
-
-    // free buffers
-    BFree(o->frames_buffer);
-    
-    // free chunks
-    BFree(o->frames_chunks);
-    
-    // free frames
-    BFree(o->frames_entries);
-    
-    // free input
-    PacketPassInterface_Free(&o->input);
-}
-
-PacketPassInterface * FragmentProtoAssembler_GetInput (FragmentProtoAssembler *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->input;
-}
diff --git a/external/badvpn_dns/client/FragmentProtoAssembler.h b/external/badvpn_dns/client/FragmentProtoAssembler.h
deleted file mode 100644
index bbc5483..0000000
--- a/external/badvpn_dns/client/FragmentProtoAssembler.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/**
- * @file FragmentProtoAssembler.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Object which decodes packets according to FragmentProto.
- */
-
-#ifndef BADVPN_CLIENT_FRAGMENTPROTOASSEMBLER_H
-#define BADVPN_CLIENT_FRAGMENTPROTOASSEMBLER_H
-
-#include <stdint.h>
-
-#include <protocol/fragmentproto.h>
-#include <misc/debug.h>
-#include <misc/compare.h>
-#include <base/DebugObject.h>
-#include <base/BLog.h>
-#include <structure/LinkedList1.h>
-#include <structure/SAvl.h>
-#include <flow/PacketPassInterface.h>
-
-#define FPA_MAX_TIME UINT32_MAX
-
-struct FragmentProtoAssembler_frame;
-
-#include "FragmentProtoAssembler_tree.h"
-#include <structure/SAvl_decl.h>
-
-struct FragmentProtoAssembler_chunk {
-    int start;
-    int len;
-};
-
-struct FragmentProtoAssembler_frame {
-    LinkedList1Node list_node; // node in free or used list
-    struct FragmentProtoAssembler_chunk *chunks; // array of chunks, up to num_chunks
-    uint8_t *buffer; // buffer with frame data, size output_mtu
-    // everything below only defined when frame entry is used
-    fragmentproto_frameid id; // frame identifier
-    uint32_t time; // packet time when the last chunk was received
-    FPAFramesTreeNode tree_node; // node fields in tree for searching frames by id
-    int num_chunks; // number of valid chunks
-    int sum; // sum of all chunks' lengths
-    int length; // length of the frame, or -1 if not yet known
-    int length_so_far; // if length=-1, current data set's upper bound
-};
-
-/**
- * Object which decodes packets according to FragmentProto.
- *
- * Input is with {@link PacketPassInterface}.
- * Output is with {@link PacketPassInterface}.
- */
-typedef struct {
-    void *user;
-    BLog_logfunc logfunc;
-    PacketPassInterface input;
-    PacketPassInterface *output;
-    int output_mtu;
-    int num_chunks;
-    uint32_t time;
-    int time_tolerance;
-    struct FragmentProtoAssembler_frame *frames_entries;
-    struct FragmentProtoAssembler_chunk *frames_chunks;
-    uint8_t *frames_buffer;
-    LinkedList1 frames_free;
-    LinkedList1 frames_used;
-    FPAFramesTree frames_used_tree;
-    int in_len;
-    uint8_t *in;
-    int in_pos;
-    DebugObject d_obj;
-} FragmentProtoAssembler;
-
-/**
- * Initializes the object.
- * {@link BLog_Init} must have been done.
- *
- * @param o the object
- * @param input_mtu maximum input packet size. Must be >=0.
- * @param output output interface
- * @param num_frames number of frames we can hold. Must be >0 and < FPA_MAX_TIME.
- *  To make the assembler tolerate out-of-order input of degree D, set to D+2.
- *  Here, D is the minimum size of a hypothetical buffer needed to order the input.
- * @param num_chunks maximum number of chunks a frame can come in. Must be >0.
- * @param pg pending group
- * @param user argument to handlers
- * @param logfunc function which prepends the log prefix using {@link BLog_Append}
- * @return 1 on success, 0 on failure
- */
-int FragmentProtoAssembler_Init (FragmentProtoAssembler *o, int input_mtu, PacketPassInterface *output, int num_frames, int num_chunks, BPendingGroup *pg, void *user, BLog_logfunc logfunc) WARN_UNUSED;
-
-/**
- * Frees the object.
- *
- * @param o the object
- */
-void FragmentProtoAssembler_Free (FragmentProtoAssembler *o);
-
-/**
- * Returns the input interface.
- *
- * @param o the object
- * @return input interface
- */
-PacketPassInterface * FragmentProtoAssembler_GetInput (FragmentProtoAssembler *o);
-
-#endif
diff --git a/external/badvpn_dns/client/FragmentProtoAssembler_tree.h b/external/badvpn_dns/client/FragmentProtoAssembler_tree.h
deleted file mode 100644
index 744c633..0000000
--- a/external/badvpn_dns/client/FragmentProtoAssembler_tree.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#define SAVL_PARAM_NAME FPAFramesTree
-#define SAVL_PARAM_FEATURE_COUNTS 0
-#define SAVL_PARAM_FEATURE_NOKEYS 0
-#define SAVL_PARAM_TYPE_ENTRY struct FragmentProtoAssembler_frame
-#define SAVL_PARAM_TYPE_KEY fragmentproto_frameid
-#define SAVL_PARAM_TYPE_ARG int
-#define SAVL_PARAM_FUN_COMPARE_ENTRIES(arg, entry1, entry2) B_COMPARE((entry1)->id, (entry2)->id)
-#define SAVL_PARAM_FUN_COMPARE_KEY_ENTRY(arg, key1, entry2) B_COMPARE((key1), (entry2)->id)
-#define SAVL_PARAM_MEMBER_NODE tree_node
diff --git a/external/badvpn_dns/client/FragmentProtoDisassembler.c b/external/badvpn_dns/client/FragmentProtoDisassembler.c
deleted file mode 100644
index e67a1dc..0000000
--- a/external/badvpn_dns/client/FragmentProtoDisassembler.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/**
- * @file FragmentProtoDisassembler.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stddef.h>
-#include <string.h>
-
-#include <misc/debug.h>
-#include <misc/byteorder.h>
-#include <misc/minmax.h>
-
-#include "client/FragmentProtoDisassembler.h"
-
-static void write_chunks (FragmentProtoDisassembler *o)
-{
-    #define IN_AVAIL (o->in_len - o->in_used)
-    #define OUT_AVAIL ((o->output_mtu - o->out_used) - (int)sizeof(struct fragmentproto_chunk_header))
-    
-    ASSERT(o->in_len >= 0)
-    ASSERT(o->out)
-    ASSERT(OUT_AVAIL > 0)
-    
-    // write chunks to output packet
-    do {
-        // calculate chunk length
-        int chunk_len = bmin_int(IN_AVAIL, OUT_AVAIL);
-        if (o->chunk_mtu > 0) {
-            chunk_len = bmin_int(chunk_len, o->chunk_mtu);
-        }
-        
-        // write chunk header
-        struct fragmentproto_chunk_header header;
-        header.frame_id = htol16(o->frame_id);
-        header.chunk_start = htol16(o->in_used);
-        header.chunk_len = htol16(chunk_len);
-        header.is_last = (chunk_len == IN_AVAIL);
-        memcpy(o->out + o->out_used, &header, sizeof(header));
-        
-        // write chunk data
-        memcpy(o->out + o->out_used + sizeof(struct fragmentproto_chunk_header), o->in + o->in_used, chunk_len);
-        
-        // increment pointers
-        o->in_used += chunk_len;
-        o->out_used += sizeof(struct fragmentproto_chunk_header) + chunk_len;
-    } while (IN_AVAIL > 0 && OUT_AVAIL > 0);
-    
-    // have we finished the input packet?
-    if (IN_AVAIL == 0) {
-        // set no input packet
-        o->in_len = -1;
-        
-        // increment frame ID
-        o->frame_id++;
-        
-        // finish input
-        PacketPassInterface_Done(&o->input);
-    }
-    
-    // should we finish the output packet?
-    if (OUT_AVAIL <= 0 || o->latency < 0) {
-        // set no output packet
-        o->out = NULL;
-        
-        // stop timer (if it's running)
-        if (o->latency >= 0) {
-            BReactor_RemoveTimer(o->reactor, &o->timer);
-        }
-        
-        // finish output
-        PacketRecvInterface_Done(&o->output, o->out_used);
-    } else {
-        // start timer if we have output and it's not running (output was empty before)
-        if (!BTimer_IsRunning(&o->timer)) {
-            BReactor_SetTimer(o->reactor, &o->timer);
-        }
-    }
-}
-
-static void input_handler_send (FragmentProtoDisassembler *o, uint8_t *data, int data_len)
-{
-    ASSERT(data_len >= 0)
-    ASSERT(o->in_len == -1)
-    
-    // set input packet
-    o->in_len = data_len;
-    o->in = data;
-    o->in_used = 0;
-    
-    // if there is no output, wait for it
-    if (!o->out) {
-        return;
-    }
-    
-    write_chunks(o);
-}
-
-static void input_handler_requestcancel (FragmentProtoDisassembler *o)
-{
-    ASSERT(o->in_len >= 0)
-    ASSERT(!o->out)
-    
-    // set no input packet
-    o->in_len = -1;
-    
-    // finish input
-    PacketPassInterface_Done(&o->input);
-}
-
-static void output_handler_recv (FragmentProtoDisassembler *o, uint8_t *data)
-{
-    ASSERT(data)
-    ASSERT(!o->out)
-    
-    // set output packet
-    o->out = data;
-    o->out_used = 0;
-    
-    // if there is no input, wait for it
-    if (o->in_len < 0) {
-        return;
-    }
-    
-    write_chunks(o);
-}
-
-static void timer_handler (FragmentProtoDisassembler *o)
-{
-    ASSERT(o->latency >= 0)
-    ASSERT(o->out)
-    ASSERT(o->in_len == -1)
-    
-    // set no output packet
-    o->out = NULL;
-    
-    // finish output
-    PacketRecvInterface_Done(&o->output, o->out_used);
-}
-
-void FragmentProtoDisassembler_Init (FragmentProtoDisassembler *o, BReactor *reactor, int input_mtu, int output_mtu, int chunk_mtu, btime_t latency)
-{
-    ASSERT(input_mtu >= 0)
-    ASSERT(input_mtu <= UINT16_MAX)
-    ASSERT(output_mtu > sizeof(struct fragmentproto_chunk_header))
-    ASSERT(chunk_mtu > 0 || chunk_mtu < 0)
-    
-    // init arguments
-    o->reactor = reactor;
-    o->output_mtu = output_mtu;
-    o->chunk_mtu = chunk_mtu;
-    o->latency = latency;
-    
-    // init input
-    PacketPassInterface_Init(&o->input, input_mtu, (PacketPassInterface_handler_send)input_handler_send, o, BReactor_PendingGroup(reactor));
-    PacketPassInterface_EnableCancel(&o->input, (PacketPassInterface_handler_requestcancel)input_handler_requestcancel);
-    
-    // init output
-    PacketRecvInterface_Init(&o->output, o->output_mtu, (PacketRecvInterface_handler_recv)output_handler_recv, o, BReactor_PendingGroup(reactor));
-    
-    // init timer
-    if (o->latency >= 0) {
-        BTimer_Init(&o->timer, o->latency, (BTimer_handler)timer_handler, o);
-    }
-    
-    // have no input packet
-    o->in_len = -1;
-    
-    // have no output packet
-    o->out = NULL;
-    
-    // start with zero frame ID
-    o->frame_id = 0;
-    
-    DebugObject_Init(&o->d_obj);
-}
-
-void FragmentProtoDisassembler_Free (FragmentProtoDisassembler *o)
-{
-    DebugObject_Free(&o->d_obj);
-
-    // free timer
-    if (o->latency >= 0) {
-        BReactor_RemoveTimer(o->reactor, &o->timer);
-    }
-    
-    // free output
-    PacketRecvInterface_Free(&o->output);
-    
-    // free input
-    PacketPassInterface_Free(&o->input);
-}
-
-PacketPassInterface * FragmentProtoDisassembler_GetInput (FragmentProtoDisassembler *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->input;
-}
-
-PacketRecvInterface * FragmentProtoDisassembler_GetOutput (FragmentProtoDisassembler *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->output;
-}
diff --git a/external/badvpn_dns/client/FragmentProtoDisassembler.h b/external/badvpn_dns/client/FragmentProtoDisassembler.h
deleted file mode 100644
index 49fe9c8..0000000
--- a/external/badvpn_dns/client/FragmentProtoDisassembler.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/**
- * @file FragmentProtoDisassembler.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Object which encodes packets into packets composed of chunks
- * according to FragmentProto.
- */
-
-#ifndef BADVPN_CLIENT_CCPROTODISASSEMBLER_H
-#define BADVPN_CLIENT_CCPROTODISASSEMBLER_H
-
-#include <stdint.h>
-
-#include <protocol/fragmentproto.h>
-#include <base/DebugObject.h>
-#include <system/BReactor.h>
-#include <system/BTime.h>
-#include <flow/PacketPassInterface.h>
-#include <flow/PacketRecvInterface.h>
-
-/**
- * Object which encodes packets into packets composed of chunks
- * according to FragmentProto.
- *
- * Input is with {@link PacketPassInterface}.
- * Output is with {@link PacketRecvInterface}.
- */
-typedef struct {
-    BReactor *reactor;
-    int output_mtu;
-    int chunk_mtu;
-    btime_t latency;
-    PacketPassInterface input;
-    PacketRecvInterface output;
-    BTimer timer;
-    int in_len;
-    uint8_t *in;
-    int in_used;
-    uint8_t *out;
-    int out_used;
-    fragmentproto_frameid frame_id;
-    DebugObject d_obj;
-} FragmentProtoDisassembler;
-
-/**
- * Initializes the object.
- *
- * @param o the object
- * @param reactor reactor we live in
- * @param input_mtu maximum input packet size. Must be >=0 and <=UINT16_MAX.
- * @param output_mtu maximum output packet size. Must be >sizeof(struct fragmentproto_chunk_header).
- * @param chunk_mtu maximum chunk size. Must be >0, or <0 for no explicit limit.
- * @param latency maximum time a pending output packet with some data can wait for more data
- *                before being sent out. If nonnegative, a timer will be used. If negative,
- *                packets will always be sent out immediately. If low latency is desired,
- *                prefer setting this to zero rather than negative.
- */
-void FragmentProtoDisassembler_Init (FragmentProtoDisassembler *o, BReactor *reactor, int input_mtu, int output_mtu, int chunk_mtu, btime_t latency);
-
-/**
- * Frees the object.
- *
- * @param o the object
- */
-void FragmentProtoDisassembler_Free (FragmentProtoDisassembler *o);
-
-/**
- * Returns the input interface.
- *
- * @param o the object
- * @return input interface
- */
-PacketPassInterface * FragmentProtoDisassembler_GetInput (FragmentProtoDisassembler *o);
-
-/**
- * Returns the output interface.
- *
- * @param o the object
- * @return output interface
- */
-PacketRecvInterface * FragmentProtoDisassembler_GetOutput (FragmentProtoDisassembler *o);
-
-#endif
diff --git a/external/badvpn_dns/client/FrameDecider.c b/external/badvpn_dns/client/FrameDecider.c
deleted file mode 100644
index e7bb4de..0000000
--- a/external/badvpn_dns/client/FrameDecider.c
+++ /dev/null
@@ -1,795 +0,0 @@
-/**
- * @file FrameDecider.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-#include <stddef.h>
-
-#include <misc/debug.h>
-#include <misc/offset.h>
-#include <misc/balloc.h>
-#include <misc/ethernet_proto.h>
-#include <misc/ipv4_proto.h>
-#include <misc/igmp_proto.h>
-#include <misc/byteorder.h>
-#include <misc/compare.h>
-#include <misc/print_macros.h>
-
-#include <client/FrameDecider.h>
-
-#include <generated/blog_channel_FrameDecider.h>
-
-#define DECIDE_STATE_NONE 1
-#define DECIDE_STATE_UNICAST 2
-#define DECIDE_STATE_FLOOD 3
-#define DECIDE_STATE_MULTICAST 4
-
-#define PeerLog(_o, ...) BLog_LogViaFunc((_o)->logfunc, (_o)->user, BLOG_CURRENT_CHANNEL, __VA_ARGS__)
-
-static int compare_macs (const uint8_t *mac1, const uint8_t *mac2)
-{
-    int c = memcmp(mac1, mac2, 6);
-    return B_COMPARE(c, 0);
-}
-
-#include "FrameDecider_macs_tree.h"
-#include <structure/SAvl_impl.h>
-
-#include "FrameDecider_groups_tree.h"
-#include <structure/SAvl_impl.h>
-
-#include "FrameDecider_multicast_tree.h"
-#include <structure/SAvl_impl.h>
-
-static void add_mac_to_peer (FrameDeciderPeer *o, uint8_t *mac)
-{
-    FrameDecider *d = o->d;
-    
-    // locate entry in tree
-    struct _FrameDecider_mac_entry *e_entry = FDMacsTree_LookupExact(&d->macs_tree, 0, mac);
-    if (e_entry) {
-        if (e_entry->peer == o) {
-            // this is our MAC; only move it to the end of the used list
-            LinkedList1_Remove(&o->mac_entries_used, &e_entry->list_node);
-            LinkedList1_Append(&o->mac_entries_used, &e_entry->list_node);
-            return;
-        }
-        
-        // some other peer has that MAC; disassociate it
-        FDMacsTree_Remove(&d->macs_tree, 0, e_entry);
-        LinkedList1_Remove(&e_entry->peer->mac_entries_used, &e_entry->list_node);
-        LinkedList1_Append(&e_entry->peer->mac_entries_free, &e_entry->list_node);
-    }
-    
-    // aquire MAC address entry, if there are no free ones reuse the oldest used one
-    LinkedList1Node *list_node;
-    struct _FrameDecider_mac_entry *entry;
-    if (list_node = LinkedList1_GetFirst(&o->mac_entries_free)) {
-        entry = UPPER_OBJECT(list_node, struct _FrameDecider_mac_entry, list_node);
-        ASSERT(entry->peer == o)
-        
-        // remove from free
-        LinkedList1_Remove(&o->mac_entries_free, &entry->list_node);
-    } else {
-        list_node = LinkedList1_GetFirst(&o->mac_entries_used);
-        ASSERT(list_node)
-        entry = UPPER_OBJECT(list_node, struct _FrameDecider_mac_entry, list_node);
-        ASSERT(entry->peer == o)
-        
-        // remove from used
-        FDMacsTree_Remove(&d->macs_tree, 0, entry);
-        LinkedList1_Remove(&o->mac_entries_used, &entry->list_node);
-    }
-    
-    PeerLog(o, BLOG_INFO, "adding MAC %02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8"", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
-    
-    // set MAC in entry
-    memcpy(entry->mac, mac, sizeof(entry->mac));
-    
-    // add to used
-    LinkedList1_Append(&o->mac_entries_used, &entry->list_node);
-    int res = FDMacsTree_Insert(&d->macs_tree, 0, entry, NULL);
-    ASSERT_EXECUTE(res)
-}
-
-static uint32_t compute_sig_for_group (uint32_t group)
-{
-    return hton32(ntoh32(group)&0x7FFFFF);
-}
-
-static uint32_t compute_sig_for_mac (uint8_t *mac)
-{
-    uint32_t sig;
-    memcpy(&sig, mac + 2, 4);
-    sig = hton32(ntoh32(sig)&0x7FFFFF);
-    return sig;
-}
-
-static void add_to_multicast (FrameDecider *d, struct _FrameDecider_group_entry *group_entry)
-{
-    // compute sig
-    uint32_t sig = compute_sig_for_group(group_entry->group);
-    
-    struct _FrameDecider_group_entry *master = FDMulticastTree_LookupExact(&d->multicast_tree, 0, sig);
-    if (master) {
-        // use existing master
-        ASSERT(master->is_master)
-        
-        // set not master
-        group_entry->is_master = 0;
-        
-        // insert to list
-        LinkedList3Node_InitAfter(&group_entry->sig_list_node, &master->sig_list_node);
-    } else {
-        // make this entry master
-        
-        // set master
-        group_entry->is_master = 1;
-        
-        // set sig
-        group_entry->master.sig = sig;
-        
-        // insert to multicast tree
-        int res = FDMulticastTree_Insert(&d->multicast_tree, 0, group_entry, NULL);
-        ASSERT_EXECUTE(res)
-        
-        // init list node
-        LinkedList3Node_InitLonely(&group_entry->sig_list_node);
-    }
-}
-
-static void remove_from_multicast (FrameDecider *d, struct _FrameDecider_group_entry *group_entry)
-{
-    // compute sig
-    uint32_t sig = compute_sig_for_group(group_entry->group);
-    
-    if (group_entry->is_master) {
-        // remove master from multicast tree
-        FDMulticastTree_Remove(&d->multicast_tree, 0, group_entry);
-        
-        if (!LinkedList3Node_IsLonely(&group_entry->sig_list_node)) {
-            // at least one more group entry for this sig; make another entry the master
-            
-            // get an entry
-            LinkedList3Node *list_node = LinkedList3Node_NextOrPrev(&group_entry->sig_list_node);
-            struct _FrameDecider_group_entry *newmaster = UPPER_OBJECT(list_node, struct _FrameDecider_group_entry, sig_list_node);
-            ASSERT(!newmaster->is_master)
-            
-            // set master
-            newmaster->is_master = 1;
-            
-            // set sig
-            newmaster->master.sig = sig;
-            
-            // insert to multicast tree
-            int res = FDMulticastTree_Insert(&d->multicast_tree, 0, newmaster, NULL);
-            ASSERT_EXECUTE(res)
-        }
-    }
-    
-    // free linked list node
-    LinkedList3Node_Free(&group_entry->sig_list_node);
-}
-
-static void add_group_to_peer (FrameDeciderPeer *o, uint32_t group)
-{
-    FrameDecider *d = o->d;
-    
-    struct _FrameDecider_group_entry *group_entry = FDGroupsTree_LookupExact(&o->groups_tree, 0, group);
-    if (group_entry) {
-        // move to end of used list
-        LinkedList1_Remove(&o->group_entries_used, &group_entry->list_node);
-        LinkedList1_Append(&o->group_entries_used, &group_entry->list_node);
-    } else {
-        PeerLog(o, BLOG_INFO, "joined group %"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8"",
-            ((uint8_t *)&group)[0], ((uint8_t *)&group)[1], ((uint8_t *)&group)[2], ((uint8_t *)&group)[3]
-        );
-        
-        // aquire group entry, if there are no free ones reuse the earliest used one
-        LinkedList1Node *node;
-        if (node = LinkedList1_GetFirst(&o->group_entries_free)) {
-            group_entry = UPPER_OBJECT(node, struct _FrameDecider_group_entry, list_node);
-            
-            // remove from free list
-            LinkedList1_Remove(&o->group_entries_free, &group_entry->list_node);
-        } else {
-            node = LinkedList1_GetFirst(&o->group_entries_used);
-            ASSERT(node)
-            group_entry = UPPER_OBJECT(node, struct _FrameDecider_group_entry, list_node);
-            
-            // remove from multicast
-            remove_from_multicast(d, group_entry);
-            
-            // remove from peer's groups tree
-            FDGroupsTree_Remove(&o->groups_tree, 0, group_entry);
-            
-            // remove from used list
-            LinkedList1_Remove(&o->group_entries_used, &group_entry->list_node);
-        }
-        
-        // add entry to used list
-        LinkedList1_Append(&o->group_entries_used, &group_entry->list_node);
-        
-        // set group address
-        group_entry->group = group;
-        
-        // insert to peer's groups tree
-        int res = FDGroupsTree_Insert(&o->groups_tree, 0, group_entry, NULL);
-        ASSERT_EXECUTE(res)
-        
-        // add to multicast
-        add_to_multicast(d, group_entry);
-    }
-    
-    // set timer
-    group_entry->timer_endtime = btime_gettime() + d->igmp_group_membership_interval;
-    BReactor_SetTimerAbsolute(d->reactor, &group_entry->timer, group_entry->timer_endtime);
-}
-
-static void remove_group_entry (struct _FrameDecider_group_entry *group_entry)
-{
-    FrameDeciderPeer *peer = group_entry->peer;
-    FrameDecider *d = peer->d;
-    
-    uint32_t group = group_entry->group;
-    
-    PeerLog(peer, BLOG_INFO, "left group %"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8"",
-        ((uint8_t *)&group)[0], ((uint8_t *)&group)[1], ((uint8_t *)&group)[2], ((uint8_t *)&group)[3]
-    );
-    
-    // remove from multicast
-    remove_from_multicast(d, group_entry);
-    
-    // remove from peer's groups tree
-    FDGroupsTree_Remove(&peer->groups_tree, 0, group_entry);
-    
-    // remove from used list
-    LinkedList1_Remove(&peer->group_entries_used, &group_entry->list_node);
-    
-    // add to free list
-    LinkedList1_Append(&peer->group_entries_free, &group_entry->list_node);
-    
-    // stop timer
-    BReactor_RemoveTimer(d->reactor, &group_entry->timer);
-}
-
-static void lower_group_timers_to_lmqt (FrameDecider *d, uint32_t group)
-{
-    // have to lower all the group timers of this group down to LMQT
-    
-    // compute sig
-    uint32_t sig = compute_sig_for_group(group);
-    
-    // look up the sig in multicast tree
-    struct _FrameDecider_group_entry *master = FDMulticastTree_LookupExact(&d->multicast_tree, 0, sig);
-    if (!master) {
-        return;
-    }
-    ASSERT(master->is_master)
-    
-    // iterate all group entries with this sig
-    LinkedList3Iterator it;
-    LinkedList3Iterator_Init(&it, LinkedList3Node_First(&master->sig_list_node), 1);
-    LinkedList3Node *sig_list_node;
-    while (sig_list_node = LinkedList3Iterator_Next(&it)) {
-        struct _FrameDecider_group_entry *group_entry = UPPER_OBJECT(sig_list_node, struct _FrameDecider_group_entry, sig_list_node);
-        
-        // skip wrong groups
-        if (group_entry->group != group) {
-            continue;
-        }
-        
-        // lower timer down to LMQT
-        btime_t now = btime_gettime();
-        if (group_entry->timer_endtime > now + d->igmp_last_member_query_time) {
-            group_entry->timer_endtime = now + d->igmp_last_member_query_time;
-            BReactor_SetTimerAbsolute(d->reactor, &group_entry->timer, group_entry->timer_endtime);
-        }
-    }
-}
-
-static void group_entry_timer_handler (struct _FrameDecider_group_entry *group_entry)
-{
-    DebugObject_Access(&group_entry->peer->d_obj);
-    
-    remove_group_entry(group_entry);
-}
-
-void FrameDecider_Init (FrameDecider *o, int max_peer_macs, int max_peer_groups, btime_t igmp_group_membership_interval, btime_t igmp_last_member_query_time, BReactor *reactor)
-{
-    ASSERT(max_peer_macs > 0)
-    ASSERT(max_peer_groups > 0)
-    
-    // init arguments
-    o->max_peer_macs = max_peer_macs;
-    o->max_peer_groups = max_peer_groups;
-    o->igmp_group_membership_interval = igmp_group_membership_interval;
-    o->igmp_last_member_query_time = igmp_last_member_query_time;
-    o->reactor = reactor;
-    
-    // init peers list
-    LinkedList1_Init(&o->peers_list);
-    
-    // init MAC tree
-    FDMacsTree_Init(&o->macs_tree);
-    
-    // init multicast tree
-    FDMulticastTree_Init(&o->multicast_tree);
-    
-    // init decide state
-    o->decide_state = DECIDE_STATE_NONE;
-    
-    // set no current flood peer
-    o->decide_flood_current = NULL;
-    
-    DebugObject_Init(&o->d_obj);
-}
-
-void FrameDecider_Free (FrameDecider *o)
-{
-    ASSERT(FDMulticastTree_IsEmpty(&o->multicast_tree))
-    ASSERT(FDMacsTree_IsEmpty(&o->macs_tree))
-    ASSERT(LinkedList1_IsEmpty(&o->peers_list))
-    DebugObject_Free(&o->d_obj);
-}
-
-void FrameDecider_AnalyzeAndDecide (FrameDecider *o, const uint8_t *frame, int frame_len)
-{
-    ASSERT(frame_len >= 0)
-    DebugObject_Access(&o->d_obj);
-    
-    // reset decide state
-    switch (o->decide_state) {
-        case DECIDE_STATE_NONE:
-            break;
-        case DECIDE_STATE_UNICAST:
-            break;
-        case DECIDE_STATE_FLOOD:
-            break;
-        case DECIDE_STATE_MULTICAST:
-            LinkedList3Iterator_Free(&o->decide_multicast_it);
-            return;
-        default:
-            ASSERT(0);
-    }
-    o->decide_state = DECIDE_STATE_NONE;
-    o->decide_flood_current = NULL;
-    
-    // analyze frame
-    
-    const uint8_t *pos = frame;
-    int len = frame_len;
-    
-    if (len < sizeof(struct ethernet_header)) {
-        return;
-    }
-    struct ethernet_header eh;
-    memcpy(&eh, pos, sizeof(eh));
-    pos += sizeof(struct ethernet_header);
-    len -= sizeof(struct ethernet_header);
-    
-    int is_igmp = 0;
-    
-    switch (ntoh16(eh.type)) {
-        case ETHERTYPE_IPV4: {
-            // check IPv4 header
-            struct ipv4_header ipv4_header;
-            if (!ipv4_check((uint8_t *)pos, len, &ipv4_header, (uint8_t **)&pos, &len)) {
-                BLog(BLOG_INFO, "decide: wrong IP packet");
-                goto out;
-            }
-            
-            // check if it's IGMP
-            if (ntoh8(ipv4_header.protocol) != IPV4_PROTOCOL_IGMP) {
-                goto out;
-            }
-            
-            // remember that it's IGMP; we have to flood IGMP frames
-            is_igmp = 1;
-            
-            // check IGMP header
-            if (len < sizeof(struct igmp_base)) {
-                BLog(BLOG_INFO, "decide: IGMP: short packet");
-                goto out;
-            }
-            struct igmp_base igmp_base;
-            memcpy(&igmp_base, pos, sizeof(igmp_base));
-            pos += sizeof(struct igmp_base);
-            len -= sizeof(struct igmp_base);
-            
-            switch (ntoh8(igmp_base.type)) {
-                case IGMP_TYPE_MEMBERSHIP_QUERY: {
-                    if (len == sizeof(struct igmp_v2_extra) && ntoh8(igmp_base.max_resp_code) != 0) {
-                        // V2 query
-                        struct igmp_v2_extra query;
-                        memcpy(&query, pos, sizeof(query));
-                        pos += sizeof(struct igmp_v2_extra);
-                        len -= sizeof(struct igmp_v2_extra);
-                        
-                        if (ntoh32(query.group) != 0) {
-                            // got a Group-Specific Query, lower group timers to LMQT
-                            lower_group_timers_to_lmqt(o, query.group);
-                        }
-                    }
-                    else if (len >= sizeof(struct igmp_v3_query_extra)) {
-                        // V3 query
-                        struct igmp_v3_query_extra query;
-                        memcpy(&query, pos, sizeof(query));
-                        pos += sizeof(struct igmp_v3_query_extra);
-                        len -= sizeof(struct igmp_v3_query_extra);
-                        
-                        // iterate sources
-                        uint16_t num_sources = ntoh16(query.number_of_sources);
-                        int i;
-                        for (i = 0; i < num_sources; i++) {
-                            // check source
-                            if (len < sizeof(struct igmp_source)) {
-                                BLog(BLOG_NOTICE, "decide: IGMP: short source");
-                                goto out;
-                            }
-                            pos += sizeof(struct igmp_source);
-                            len -= sizeof(struct igmp_source);
-                        }
-                        
-                        if (ntoh32(query.group) != 0 && num_sources == 0) {
-                            // got a Group-Specific Query, lower group timers to LMQT
-                            lower_group_timers_to_lmqt(o, query.group);
-                        }
-                    }
-                } break;
-            }
-        } break;
-    }
-    
-out:;
-    
-    const uint8_t broadcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-    const uint8_t multicast_mac_header[] = {0x01, 0x00, 0x5e};
-    
-    // if it's broadcast or IGMP, flood it
-    if (is_igmp || !memcmp(eh.dest, broadcast_mac, sizeof(broadcast_mac))) {
-        o->decide_state = DECIDE_STATE_FLOOD;
-        o->decide_flood_current = LinkedList1_GetFirst(&o->peers_list);
-        return;
-    }
-    
-    // if it's multicast, forward to all peers with the given sig
-    if (!memcmp(eh.dest, multicast_mac_header, sizeof(multicast_mac_header))) {
-        // extract group's sig from destination MAC
-        uint32_t sig = compute_sig_for_mac(eh.dest);
-        
-        // look up the sig in multicast tree
-        struct _FrameDecider_group_entry *master = FDMulticastTree_LookupExact(&o->multicast_tree, 0, sig);
-        if (master) {
-            ASSERT(master->is_master)
-            
-            o->decide_state = DECIDE_STATE_MULTICAST;
-            LinkedList3Iterator_Init(&o->decide_multicast_it, LinkedList3Node_First(&master->sig_list_node), 1);
-        }
-        
-        return;
-    }
-    
-    // look for MAC entry
-    struct _FrameDecider_mac_entry *entry = FDMacsTree_LookupExact(&o->macs_tree, 0, eh.dest);
-    if (entry) {
-        o->decide_state = DECIDE_STATE_UNICAST;
-        o->decide_unicast_peer = entry->peer;
-        return;
-    }
-    
-    // unknown destination MAC, flood
-    o->decide_state = DECIDE_STATE_FLOOD;
-    o->decide_flood_current = LinkedList1_GetFirst(&o->peers_list);
-    return;
-}
-
-FrameDeciderPeer * FrameDecider_NextDestination (FrameDecider *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    switch (o->decide_state) {
-        case DECIDE_STATE_NONE: {
-            return NULL;
-        } break;
-            
-        case DECIDE_STATE_UNICAST: {
-            o->decide_state = DECIDE_STATE_NONE;
-            
-            return o->decide_unicast_peer;
-        } break;
-        
-        case DECIDE_STATE_FLOOD: {
-            if (!o->decide_flood_current) {
-                o->decide_state = DECIDE_STATE_NONE;
-                return NULL;
-            }
-            
-            LinkedList1Node *list_node = o->decide_flood_current;
-            o->decide_flood_current = LinkedList1Node_Next(o->decide_flood_current);
-            
-            FrameDeciderPeer *peer = UPPER_OBJECT(list_node, FrameDeciderPeer, list_node);
-            
-            return peer;
-        } break;
-        
-        case DECIDE_STATE_MULTICAST: {
-            LinkedList3Node *list_node = LinkedList3Iterator_Next(&o->decide_multicast_it);
-            if (!list_node) {
-                o->decide_state = DECIDE_STATE_NONE;
-                return NULL;
-            }
-            struct _FrameDecider_group_entry *group_entry = UPPER_OBJECT(list_node, struct _FrameDecider_group_entry, sig_list_node);
-            
-            return group_entry->peer;
-        } break;
-        
-        default:
-            ASSERT(0);
-            return NULL;
-    }
-}
-
-int FrameDeciderPeer_Init (FrameDeciderPeer *o, FrameDecider *d, void *user, BLog_logfunc logfunc)
-{
-    // init arguments
-    o->d = d;
-    o->user = user;
-    o->logfunc = logfunc;
-    
-    // allocate MAC entries
-    if (!(o->mac_entries = (struct _FrameDecider_mac_entry *)BAllocArray(d->max_peer_macs, sizeof(struct _FrameDecider_mac_entry)))) {
-        PeerLog(o, BLOG_ERROR, "failed to allocate MAC entries");
-        goto fail0;
-    }
-    
-    // allocate group entries
-    if (!(o->group_entries = (struct _FrameDecider_group_entry *)BAllocArray(d->max_peer_groups, sizeof(struct _FrameDecider_group_entry)))) {
-        PeerLog(o, BLOG_ERROR, "failed to allocate group entries");
-        goto fail1;
-    }
-    
-    // insert to peers list
-    LinkedList1_Append(&d->peers_list, &o->list_node);
-    
-    // init MAC entry lists
-    LinkedList1_Init(&o->mac_entries_free);
-    LinkedList1_Init(&o->mac_entries_used);
-    
-    // initialize MAC entries
-    for (int i = 0; i < d->max_peer_macs; i++) {
-        struct _FrameDecider_mac_entry *entry = &o->mac_entries[i];
-        
-        // set peer
-        entry->peer = o;
-        
-        // insert to free list
-        LinkedList1_Append(&o->mac_entries_free, &entry->list_node);
-    }
-    
-    // init group entry lists
-    LinkedList1_Init(&o->group_entries_free);
-    LinkedList1_Init(&o->group_entries_used);
-    
-    // initialize group entries
-    for (int i = 0; i < d->max_peer_groups; i++) {
-        struct _FrameDecider_group_entry *entry = &o->group_entries[i];
-        
-        // set peer
-        entry->peer = o;
-        
-        // insert to free list
-        LinkedList1_Append(&o->group_entries_free, &entry->list_node);
-        
-        // init timer
-        BTimer_Init(&entry->timer, 0, (BTimer_handler)group_entry_timer_handler, entry);
-    }
-    
-    // initialize groups tree
-    FDGroupsTree_Init(&o->groups_tree);
-    
-    DebugObject_Init(&o->d_obj);
-    
-    return 1;
-    
-fail1:
-    BFree(o->mac_entries);
-fail0:
-    return 0;
-}
-
-void FrameDeciderPeer_Free (FrameDeciderPeer *o)
-{
-    DebugObject_Free(&o->d_obj);
-    
-    FrameDecider *d = o->d;
-    
-    // remove decide unicast reference
-    if (d->decide_state == DECIDE_STATE_UNICAST && d->decide_unicast_peer == o) {
-        d->decide_state = DECIDE_STATE_NONE;
-    }
-    
-    LinkedList1Node *node;
-    
-    // free group entries
-    for (node = LinkedList1_GetFirst(&o->group_entries_used); node; node = LinkedList1Node_Next(node)) {
-        struct _FrameDecider_group_entry *entry = UPPER_OBJECT(node, struct _FrameDecider_group_entry, list_node);
-        
-        // remove from multicast
-        remove_from_multicast(d, entry);
-        
-        // stop timer
-        BReactor_RemoveTimer(d->reactor, &entry->timer);
-    }
-    
-    // remove used MAC entries from tree
-    for (node = LinkedList1_GetFirst(&o->mac_entries_used); node; node = LinkedList1Node_Next(node)) {
-        struct _FrameDecider_mac_entry *entry = UPPER_OBJECT(node, struct _FrameDecider_mac_entry, list_node);
-        
-        // remove from tree
-        FDMacsTree_Remove(&d->macs_tree, 0, entry);
-    }
-    
-    // remove from peers list
-    if (d->decide_flood_current == &o->list_node) {
-        d->decide_flood_current = LinkedList1Node_Next(d->decide_flood_current);
-    }
-    LinkedList1_Remove(&d->peers_list, &o->list_node);
-    
-    // free group entries
-    BFree(o->group_entries);
-    
-    // free MAC entries
-    BFree(o->mac_entries);
-}
-
-void FrameDeciderPeer_Analyze (FrameDeciderPeer *o, const uint8_t *frame, int frame_len)
-{
-    ASSERT(frame_len >= 0)
-    DebugObject_Access(&o->d_obj);
-    
-    const uint8_t *pos = frame;
-    int len = frame_len;
-    
-    if (len < sizeof(struct ethernet_header)) {
-        goto out;
-    }
-    struct ethernet_header eh;
-    memcpy(&eh, pos, sizeof(eh));
-    pos += sizeof(struct ethernet_header);
-    len -= sizeof(struct ethernet_header);
-    
-    // register source MAC address with this peer
-    add_mac_to_peer(o, eh.source);
-    
-    switch (ntoh16(eh.type)) {
-        case ETHERTYPE_IPV4: {
-            // check IPv4 header
-            struct ipv4_header ipv4_header;
-            if (!ipv4_check((uint8_t *)pos, len, &ipv4_header, (uint8_t **)&pos, &len)) {
-                PeerLog(o, BLOG_INFO, "analyze: wrong IP packet");
-                goto out;
-            }
-            
-            // check if it's IGMP
-            if (ntoh8(ipv4_header.protocol) != IPV4_PROTOCOL_IGMP) {
-                goto out;
-            }
-            
-            // check IGMP header
-            if (len < sizeof(struct igmp_base)) {
-                PeerLog(o, BLOG_INFO, "analyze: IGMP: short packet");
-                goto out;
-            }
-            struct igmp_base igmp_base;
-            memcpy(&igmp_base, pos, sizeof(igmp_base));
-            pos += sizeof(struct igmp_base);
-            len -= sizeof(struct igmp_base);
-            
-            switch (ntoh8(igmp_base.type)) {
-                case IGMP_TYPE_V2_MEMBERSHIP_REPORT: {
-                    // check extra
-                    if (len < sizeof(struct igmp_v2_extra)) {
-                        PeerLog(o, BLOG_INFO, "analyze: IGMP: short v2 report");
-                        goto out;
-                    }
-                    struct igmp_v2_extra report;
-                    memcpy(&report, pos, sizeof(report));
-                    pos += sizeof(struct igmp_v2_extra);
-                    len -= sizeof(struct igmp_v2_extra);
-                    
-                    // add to group
-                    add_group_to_peer(o, report.group);
-                } break;
-                
-                case IGMP_TYPE_V3_MEMBERSHIP_REPORT: {
-                    // check extra
-                    if (len < sizeof(struct igmp_v3_report_extra)) {
-                        PeerLog(o, BLOG_INFO, "analyze: IGMP: short v3 report");
-                        goto out;
-                    }
-                    struct igmp_v3_report_extra report;
-                    memcpy(&report, pos, sizeof(report));
-                    pos += sizeof(struct igmp_v3_report_extra);
-                    len -= sizeof(struct igmp_v3_report_extra);
-                    
-                    // iterate records
-                    uint16_t num_records = ntoh16(report.number_of_group_records);
-                    for (int i = 0; i < num_records; i++) {
-                        // check record
-                        if (len < sizeof(struct igmp_v3_report_record)) {
-                            PeerLog(o, BLOG_INFO, "analyze: IGMP: short record header");
-                            goto out;
-                        }
-                        struct igmp_v3_report_record record;
-                        memcpy(&record, pos, sizeof(record));
-                        pos += sizeof(struct igmp_v3_report_record);
-                        len -= sizeof(struct igmp_v3_report_record);
-                        
-                        // iterate sources
-                        uint16_t num_sources = ntoh16(record.number_of_sources);
-                        int j;
-                        for (j = 0; j < num_sources; j++) {
-                            // check source
-                            if (len < sizeof(struct igmp_source)) {
-                                PeerLog(o, BLOG_INFO, "analyze: IGMP: short source");
-                                goto out;
-                            }
-                            pos += sizeof(struct igmp_source);
-                            len -= sizeof(struct igmp_source);
-                        }
-                        
-                        // check aux data
-                        uint16_t aux_len = ntoh16(record.aux_data_len);
-                        if (len < aux_len) {
-                            PeerLog(o, BLOG_INFO, "analyze: IGMP: short record aux data");
-                            goto out;
-                        }
-                        pos += aux_len;
-                        len -= aux_len;
-                        
-                        switch (record.type) {
-                            case IGMP_RECORD_TYPE_MODE_IS_INCLUDE:
-                            case IGMP_RECORD_TYPE_CHANGE_TO_INCLUDE_MODE:
-                                if (num_sources != 0) {
-                                    add_group_to_peer(o, record.group);
-                                }
-                                break;
-                            case IGMP_RECORD_TYPE_MODE_IS_EXCLUDE:
-                            case IGMP_RECORD_TYPE_CHANGE_TO_EXCLUDE_MODE:
-                                add_group_to_peer(o, record.group);
-                                break;
-                        }
-                    }
-                } break;
-            }
-        } break;
-    }
-    
-out:;
-}
diff --git a/external/badvpn_dns/client/FrameDecider.h b/external/badvpn_dns/client/FrameDecider.h
deleted file mode 100644
index f2a2937..0000000
--- a/external/badvpn_dns/client/FrameDecider.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/**
- * @file FrameDecider.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Mudule which decides to which peers frames from the device are to be
- * forwarded.
- */
-
-#ifndef BADVPN_CLIENT_FRAMEDECIDER_H
-#define BADVPN_CLIENT_FRAMEDECIDER_H
-
-#include <stdint.h>
-
-#include <structure/LinkedList1.h>
-#include <structure/LinkedList3.h>
-#include <structure/SAvl.h>
-#include <base/DebugObject.h>
-#include <base/BLog.h>
-#include <system/BReactor.h>
-
-struct _FrameDeciderPeer;
-struct _FrameDecider_mac_entry;
-struct _FrameDecider_group_entry;
-
-typedef const uint8_t *FDMacsTree_key;
-
-#include "FrameDecider_macs_tree.h"
-#include <structure/SAvl_decl.h>
-
-#include "FrameDecider_groups_tree.h"
-#include <structure/SAvl_decl.h>
-
-#include "FrameDecider_multicast_tree.h"
-#include <structure/SAvl_decl.h>
-
-struct _FrameDecider_mac_entry {
-    struct _FrameDeciderPeer *peer;
-    LinkedList1Node list_node; // node in FrameDeciderPeer.mac_entries_free or FrameDeciderPeer.mac_entries_used
-    // defined when used:
-    uint8_t mac[6];
-    FDMacsTreeNode tree_node; // node in FrameDecider.macs_tree, indexed by mac
-};
-
-struct _FrameDecider_group_entry {
-    struct _FrameDeciderPeer *peer;
-    LinkedList1Node list_node; // node in FrameDeciderPeer.group_entries_free or FrameDeciderPeer.group_entries_used
-    BTimer timer; // timer for removing the group entry, running when used
-    // defined when used:
-    // basic group data
-    uint32_t group; // group address
-    FDGroupsTreeNode tree_node; // node in FrameDeciderPeer.groups_tree, indexed by group
-    // all that folows is managed by add_to_multicast() and remove_from_multicast()
-    LinkedList3Node sig_list_node; // node in list of group entries with the same sig
-    btime_t timer_endtime;
-    int is_master;
-    // defined when used and we are master:
-    struct {
-        uint32_t sig; // last 23 bits of group address
-        FDMulticastTreeNode tree_node; // node in FrameDecider.multicast_tree, indexed by sig
-    } master;
-};
-
-/**
- * Object that represents a local device.
- */
-typedef struct {
-    int max_peer_macs;
-    int max_peer_groups;
-    btime_t igmp_group_membership_interval;
-    btime_t igmp_last_member_query_time;
-    BReactor *reactor;
-    LinkedList1 peers_list;
-    FDMacsTree macs_tree;
-    FDMulticastTree multicast_tree;
-    int decide_state;
-    LinkedList1Node *decide_flood_current;
-    struct _FrameDeciderPeer *decide_unicast_peer;
-    LinkedList3Iterator decide_multicast_it;
-    DebugObject d_obj;
-} FrameDecider;
-
-/**
- * Object that represents a peer that a local device can send frames to.
- */
-typedef struct _FrameDeciderPeer {
-    FrameDecider *d;
-    void *user;
-    BLog_logfunc logfunc;
-    struct _FrameDecider_mac_entry *mac_entries;
-    struct _FrameDecider_group_entry *group_entries;
-    LinkedList1Node list_node; // node in FrameDecider.peers_list
-    LinkedList1 mac_entries_free;
-    LinkedList1 mac_entries_used;
-    LinkedList1 group_entries_free;
-    LinkedList1 group_entries_used;
-    FDGroupsTree groups_tree;
-    DebugObject d_obj;
-} FrameDeciderPeer;
-
-/**
- * Initializes the object.
- * 
- * @param o the object
- * @param max_peer_macs maximum number of MAC addresses a peer may posess. Must be >0.
- * @param max_peer_groups maximum number of multicast groups a peer may belong to. Must be >0.
- * @param igmp_group_membership_interval IGMP Group Membership Interval value. When a join
- *        is detected for a peer in {@link FrameDeciderPeer_Analyze}, this is how long we wait
- *        for another join before we remove the group from the peer. Note that the group may
- *        be removed sooner if the peer fails to respond to a Group-Specific Query (see below).
- * @param igmp_last_member_query_time IGMP Last Member Query Time value. When a Group-Specific
- *        Query is detected in {@link FrameDecider_AnalyzeAndDecide}, this is how long we wait for a peer
- *        belonging to the group to send a join before we remove the group from it.
- */
-void FrameDecider_Init (FrameDecider *o, int max_peer_macs, int max_peer_groups, btime_t igmp_group_membership_interval, btime_t igmp_last_member_query_time, BReactor *reactor);
-
-/**
- * Frees the object.
- * There must be no {@link FrameDeciderPeer} objects using this decider.
- * 
- * @param o the object
- */
-void FrameDecider_Free (FrameDecider *o);
-
-/**
- * Analyzes a frame read from the local device and starts deciding which peers
- * the frame should be forwarded to.
- * 
- * @param o the object
- * @param frame frame data
- * @param frame_len frame length. Must be >=0.
- */
-void FrameDecider_AnalyzeAndDecide (FrameDecider *o, const uint8_t *frame, int frame_len);
-
-/**
- * Returns the next peer that the frame submitted to {@link FrameDecider_AnalyzeAndDecide} should be
- * forwarded to.
- * 
- * @param o the object
- * @return peer to forward the frame to, or NULL if no more
- */
-FrameDeciderPeer * FrameDecider_NextDestination (FrameDecider *o);
-
-/**
- * Initializes the object.
- * 
- * @param o the object
- * @param d decider this peer will belong to
- * @param user argument to log function
- * @param logfunc function which prepends the log prefix using {@link BLog_Append}
- * @return 1 on success, 0 on failure
- */
-int FrameDeciderPeer_Init (FrameDeciderPeer *o, FrameDecider *d, void *user, BLog_logfunc logfunc) WARN_UNUSED;
-
-/**
- * Frees the object.
- * 
- * @param o the object
- */
-void FrameDeciderPeer_Free (FrameDeciderPeer *o);
-
-/**
- * Analyzes a frame received from the peer.
- * 
- * @param o the object
- * @param frame frame data
- * @param frame_len frame length. Must be >=0.
- */
-void FrameDeciderPeer_Analyze (FrameDeciderPeer *o, const uint8_t *frame, int frame_len);
-
-#endif
diff --git a/external/badvpn_dns/client/FrameDecider_groups_tree.h b/external/badvpn_dns/client/FrameDecider_groups_tree.h
deleted file mode 100644
index b52a947..0000000
--- a/external/badvpn_dns/client/FrameDecider_groups_tree.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#define SAVL_PARAM_NAME FDGroupsTree
-#define SAVL_PARAM_FEATURE_COUNTS 0
-#define SAVL_PARAM_FEATURE_NOKEYS 0
-#define SAVL_PARAM_TYPE_ENTRY struct _FrameDecider_group_entry
-#define SAVL_PARAM_TYPE_KEY uint32_t
-#define SAVL_PARAM_TYPE_ARG int
-#define SAVL_PARAM_FUN_COMPARE_ENTRIES(arg, entry1, entry2) B_COMPARE((entry1)->group, (entry2)->group)
-#define SAVL_PARAM_FUN_COMPARE_KEY_ENTRY(arg, key1, entry2) B_COMPARE((key1), (entry2)->group)
-#define SAVL_PARAM_MEMBER_NODE tree_node
diff --git a/external/badvpn_dns/client/FrameDecider_macs_tree.h b/external/badvpn_dns/client/FrameDecider_macs_tree.h
deleted file mode 100644
index 2145918..0000000
--- a/external/badvpn_dns/client/FrameDecider_macs_tree.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#define SAVL_PARAM_NAME FDMacsTree
-#define SAVL_PARAM_FEATURE_COUNTS 0
-#define SAVL_PARAM_FEATURE_NOKEYS 0
-#define SAVL_PARAM_TYPE_ENTRY struct _FrameDecider_mac_entry
-#define SAVL_PARAM_TYPE_KEY FDMacsTree_key
-#define SAVL_PARAM_TYPE_ARG int
-#define SAVL_PARAM_FUN_COMPARE_ENTRIES(arg, entry1, entry2) compare_macs((entry1)->mac, (entry2)->mac)
-#define SAVL_PARAM_FUN_COMPARE_KEY_ENTRY(arg, key1, entry2) compare_macs((key1), (entry2)->mac)
-#define SAVL_PARAM_MEMBER_NODE tree_node
diff --git a/external/badvpn_dns/client/FrameDecider_multicast_tree.h b/external/badvpn_dns/client/FrameDecider_multicast_tree.h
deleted file mode 100644
index 2731684..0000000
--- a/external/badvpn_dns/client/FrameDecider_multicast_tree.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#define SAVL_PARAM_NAME FDMulticastTree
-#define SAVL_PARAM_FEATURE_COUNTS 0
-#define SAVL_PARAM_FEATURE_NOKEYS 0
-#define SAVL_PARAM_TYPE_ENTRY struct _FrameDecider_group_entry
-#define SAVL_PARAM_TYPE_KEY uint32_t
-#define SAVL_PARAM_TYPE_ARG int
-#define SAVL_PARAM_FUN_COMPARE_ENTRIES(arg, entry1, entry2) B_COMPARE((entry1)->master.sig, (entry2)->master.sig)
-#define SAVL_PARAM_FUN_COMPARE_KEY_ENTRY(arg, key1, entry2) B_COMPARE((key1), (entry2)->master.sig)
-#define SAVL_PARAM_MEMBER_NODE master.tree_node
diff --git a/external/badvpn_dns/client/PasswordListener.c b/external/badvpn_dns/client/PasswordListener.c
deleted file mode 100644
index 5ec573b..0000000
--- a/external/badvpn_dns/client/PasswordListener.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/**
- * @file PasswordListener.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-
-#include <prerror.h>
-
-#include <ssl.h>
-
-#include <misc/offset.h>
-#include <misc/byteorder.h>
-#include <misc/balloc.h>
-#include <misc/compare.h>
-#include <base/BLog.h>
-#include <security/BRandom.h>
-#include <nspr_support/DummyPRFileDesc.h>
-
-#include <client/PasswordListener.h>
-
-#include <generated/blog_channel_PasswordListener.h>
-
-static int password_comparator (void *user, uint64_t *p1, uint64_t *p2);
-static void remove_client (struct PasswordListenerClient *client);
-static void listener_handler (PasswordListener *l);
-static void client_connection_handler (struct PasswordListenerClient *client, int event);
-static void client_sslcon_handler (struct PasswordListenerClient *client, int event);
-static void client_receiver_handler (struct PasswordListenerClient *client);
-
-int password_comparator (void *user, uint64_t *p1, uint64_t *p2)
-{
-    return B_COMPARE(*p1, *p2);
-}
-
-void remove_client (struct PasswordListenerClient *client)
-{
-    PasswordListener *l = client->l;
-    
-    // stop using any buffers before they get freed
-    if (l->ssl) {
-        BSSLConnection_ReleaseBuffers(&client->sslcon);
-    }
-    
-    // free receiver
-    SingleStreamReceiver_Free(&client->receiver);
-    
-    // free SSL
-    if (l->ssl) {
-        BSSLConnection_Free(&client->sslcon);
-        ASSERT_FORCE(PR_Close(client->sock->ssl_prfd) == PR_SUCCESS)
-    }
-    
-    // free connection interfaces
-    BConnection_RecvAsync_Free(&client->sock->con);
-    BConnection_SendAsync_Free(&client->sock->con);
-    
-    // free connection
-    BConnection_Free(&client->sock->con);
-    
-    // free sslsocket structure
-    free(client->sock);
-    
-    // move to free list
-    LinkedList1_Remove(&l->clients_used, &client->list_node);
-    LinkedList1_Append(&l->clients_free, &client->list_node);
-}
-
-void listener_handler (PasswordListener *l)
-{
-    DebugObject_Access(&l->d_obj);
-    
-    // obtain client entry
-    if (LinkedList1_IsEmpty(&l->clients_free)) {
-        struct PasswordListenerClient *client = UPPER_OBJECT(LinkedList1_GetFirst(&l->clients_used), struct PasswordListenerClient, list_node);
-        remove_client(client);
-    }
-    struct PasswordListenerClient *client = UPPER_OBJECT(LinkedList1_GetLast(&l->clients_free), struct PasswordListenerClient, list_node);
-    LinkedList1_Remove(&l->clients_free, &client->list_node);
-    LinkedList1_Append(&l->clients_used, &client->list_node);
-    
-    // allocate sslsocket structure
-    if (!(client->sock = (sslsocket *)malloc(sizeof(*client->sock)))) {
-        BLog(BLOG_ERROR, "malloc failedt");
-        goto fail0;
-    }
-    
-    // accept connection
-    if (!BConnection_Init(&client->sock->con, BConnection_source_listener(&l->listener, NULL), l->bsys, client, (BConnection_handler)client_connection_handler)) {
-        BLog(BLOG_ERROR, "BConnection_Init failed");
-        goto fail1;
-    }
-    
-    BLog(BLOG_INFO, "Connection accepted");
-    
-    // init connection interfaces
-    BConnection_SendAsync_Init(&client->sock->con);
-    BConnection_RecvAsync_Init(&client->sock->con);
-    
-    StreamPassInterface *send_if = BConnection_SendAsync_GetIf(&client->sock->con);
-    StreamRecvInterface *recv_if = BConnection_RecvAsync_GetIf(&client->sock->con);
-    
-    if (l->ssl) {
-        // create bottom NSPR file descriptor
-        if (!BSSLConnection_MakeBackend(&client->sock->bottom_prfd, send_if, recv_if, l->twd, l->ssl_flags)) {
-            BLog(BLOG_ERROR, "BSSLConnection_MakeBackend failed");
-            goto fail2;
-        }
-        
-        // create SSL file descriptor from the bottom NSPR file descriptor
-        if (!(client->sock->ssl_prfd = SSL_ImportFD(l->model_prfd, &client->sock->bottom_prfd))) {
-            ASSERT_FORCE(PR_Close(&client->sock->bottom_prfd) == PR_SUCCESS)
-            goto fail2;
-        }
-        
-        // set server mode
-        if (SSL_ResetHandshake(client->sock->ssl_prfd, PR_TRUE) != SECSuccess) {
-            BLog(BLOG_ERROR, "SSL_ResetHandshake failed");
-            goto fail3;
-        }
-        
-        // set require client certificate
-        if (SSL_OptionSet(client->sock->ssl_prfd, SSL_REQUEST_CERTIFICATE, PR_TRUE) != SECSuccess) {
-            BLog(BLOG_ERROR, "SSL_OptionSet(SSL_REQUEST_CERTIFICATE) failed");
-            goto fail3;
-        }
-        if (SSL_OptionSet(client->sock->ssl_prfd, SSL_REQUIRE_CERTIFICATE, PR_TRUE) != SECSuccess) {
-            BLog(BLOG_ERROR, "SSL_OptionSet(SSL_REQUIRE_CERTIFICATE) failed");
-            goto fail3;
-        }
-        
-        // initialize SSLConnection
-        BSSLConnection_Init(&client->sslcon, client->sock->ssl_prfd, 0, BReactor_PendingGroup(l->bsys), client, (BSSLConnection_handler)client_sslcon_handler);
-        
-        send_if = BSSLConnection_GetSendIf(&client->sslcon);
-        recv_if = BSSLConnection_GetRecvIf(&client->sslcon);
-    }
-    
-    // init receiver
-    SingleStreamReceiver_Init(&client->receiver, (uint8_t *)&client->recv_buffer, sizeof(client->recv_buffer), recv_if, BReactor_PendingGroup(l->bsys), client, (SingleStreamReceiver_handler)client_receiver_handler);
-    
-    return;
-    
-    // cleanup on error
-fail3:
-    if (l->ssl) {
-        ASSERT_FORCE(PR_Close(client->sock->ssl_prfd) == PR_SUCCESS)
-    }
-fail2:
-    BConnection_RecvAsync_Free(&client->sock->con);
-    BConnection_SendAsync_Free(&client->sock->con);
-    BConnection_Free(&client->sock->con);
-fail1:
-    free(client->sock);
-fail0:
-    LinkedList1_Remove(&l->clients_used, &client->list_node);
-    LinkedList1_Append(&l->clients_free, &client->list_node);
-}
-
-void client_connection_handler (struct PasswordListenerClient *client, int event)
-{
-    PasswordListener *l = client->l;
-    DebugObject_Access(&l->d_obj);
-    
-    if (event == BCONNECTION_EVENT_RECVCLOSED) {
-        BLog(BLOG_INFO, "connection closed");
-    } else {
-        BLog(BLOG_INFO, "connection error");
-    }
-    
-    remove_client(client);
-}
-
-void client_sslcon_handler (struct PasswordListenerClient *client, int event)
-{
-    PasswordListener *l = client->l;
-    DebugObject_Access(&l->d_obj);
-    ASSERT(l->ssl)
-    ASSERT(event == BSSLCONNECTION_EVENT_ERROR)
-    
-    BLog(BLOG_INFO, "SSL error");
-    
-    remove_client(client);
-}
-
-void client_receiver_handler (struct PasswordListenerClient *client)
-{
-    PasswordListener *l = client->l;
-    DebugObject_Access(&l->d_obj);
-    
-    // check password
-    uint64_t received_pass = ltoh64(client->recv_buffer);
-    BAVLNode *pw_tree_node = BAVL_LookupExact(&l->passwords, &received_pass);
-    if (!pw_tree_node) {
-        BLog(BLOG_WARNING, "unknown password");
-        remove_client(client);
-        return;
-    }
-    PasswordListener_pwentry *pw_entry = UPPER_OBJECT(pw_tree_node, PasswordListener_pwentry, tree_node);
-    
-    BLog(BLOG_INFO, "Password recognized");
-    
-    // remove password entry
-    BAVL_Remove(&l->passwords, &pw_entry->tree_node);
-    
-    // stop using any buffers before they get freed
-    if (l->ssl) {
-        BSSLConnection_ReleaseBuffers(&client->sslcon);
-    }
-    
-    // free receiver
-    SingleStreamReceiver_Free(&client->receiver);
-    
-    if (l->ssl) {
-        // free SSL connection
-        BSSLConnection_Free(&client->sslcon);
-    } else {
-        // free connection interfaces
-        BConnection_RecvAsync_Free(&client->sock->con);
-        BConnection_SendAsync_Free(&client->sock->con);
-    }
-    
-    // remove connection handler
-    BConnection_SetHandlers(&client->sock->con, NULL, NULL);
-    
-    // move client entry to free list
-    LinkedList1_Remove(&l->clients_used, &client->list_node);
-    LinkedList1_Append(&l->clients_free, &client->list_node);
-    
-    // give the socket to the handler
-    pw_entry->handler_client(pw_entry->user, client->sock);
-    return;
-}
-
-int PasswordListener_Init (PasswordListener *l, BReactor *bsys, BThreadWorkDispatcher *twd, BAddr listen_addr, int max_clients, int ssl, int ssl_flags, CERTCertificate *cert, SECKEYPrivateKey *key)
-{
-    ASSERT(BConnection_AddressSupported(listen_addr))
-    ASSERT(max_clients > 0)
-    ASSERT(ssl == 0 || ssl == 1)
-    
-    // init arguments
-    l->bsys = bsys;
-    l->twd = twd;
-    l->ssl = ssl;
-    l->ssl_flags = ssl_flags;
-    
-    // allocate client entries
-    if (!(l->clients_data = (struct PasswordListenerClient *)BAllocArray(max_clients, sizeof(struct PasswordListenerClient)))) {
-        BLog(BLOG_ERROR, "BAllocArray failed");
-        goto fail0;
-    }
-    
-    if (l->ssl) {
-        // initialize model SSL fd
-        DummyPRFileDesc_Create(&l->model_dprfd);
-        if (!(l->model_prfd = SSL_ImportFD(NULL, &l->model_dprfd))) {
-            BLog(BLOG_ERROR, "SSL_ImportFD failed");
-            ASSERT_FORCE(PR_Close(&l->model_dprfd) == PR_SUCCESS)
-            goto fail1;
-        }
-        
-        // set server certificate
-        if (SSL_ConfigSecureServer(l->model_prfd, cert, key, NSS_FindCertKEAType(cert)) != SECSuccess) {
-            BLog(BLOG_ERROR, "SSL_ConfigSecureServer failed");
-            goto fail2;
-        }
-    }
-    
-    // initialize client entries
-    LinkedList1_Init(&l->clients_free);
-    LinkedList1_Init(&l->clients_used);
-    for (int i = 0; i < max_clients; i++) {
-        struct PasswordListenerClient *conn = &l->clients_data[i];
-        conn->l = l;
-        LinkedList1_Append(&l->clients_free, &conn->list_node);
-    }
-    
-    // initialize passwords tree
-    BAVL_Init(&l->passwords, OFFSET_DIFF(PasswordListener_pwentry, password, tree_node), (BAVL_comparator)password_comparator, NULL);
-    
-    // initialize listener
-    if (!BListener_Init(&l->listener, listen_addr,  l->bsys, l, (BListener_handler)listener_handler)) {
-        BLog(BLOG_ERROR, "Listener_Init failed");
-        goto fail2;
-    }
-    
-    DebugObject_Init(&l->d_obj);
-    return 1;
-    
-    // cleanup
-fail2:
-    if (l->ssl) {
-        ASSERT_FORCE(PR_Close(l->model_prfd) == PR_SUCCESS)
-    }
-fail1:
-    BFree(l->clients_data);
-fail0:
-    return 0;
-}
-
-void PasswordListener_Free (PasswordListener *l)
-{
-    DebugObject_Free(&l->d_obj);
-
-    // free clients
-    LinkedList1Node *node;
-    while (node = LinkedList1_GetFirst(&l->clients_used)) {
-        struct PasswordListenerClient *client = UPPER_OBJECT(node, struct PasswordListenerClient, list_node);
-        remove_client(client);
-    }
-    
-    // free listener
-    BListener_Free(&l->listener);
-    
-    // free model SSL file descriptor
-    if (l->ssl) {
-        ASSERT_FORCE(PR_Close(l->model_prfd) == PR_SUCCESS)
-    }
-    
-    // free client entries
-    BFree(l->clients_data);
-}
-
-uint64_t PasswordListener_AddEntry (PasswordListener *l, PasswordListener_pwentry *entry, PasswordListener_handler_client handler_client, void *user)
-{
-    DebugObject_Access(&l->d_obj);
-    
-    while (1) {
-        // generate password
-        BRandom_randomize((uint8_t *)&entry->password, sizeof(entry->password));
-        
-        // try inserting
-        if (BAVL_Insert(&l->passwords, &entry->tree_node, NULL)) {
-            break;
-        }
-    }
-    
-    entry->handler_client = handler_client;
-    entry->user = user;
-    
-    return entry->password;
-}
-
-void PasswordListener_RemoveEntry (PasswordListener *l, PasswordListener_pwentry *entry)
-{
-    DebugObject_Access(&l->d_obj);
-    
-    // remove
-    BAVL_Remove(&l->passwords, &entry->tree_node);
-}
diff --git a/external/badvpn_dns/client/PasswordListener.h b/external/badvpn_dns/client/PasswordListener.h
deleted file mode 100644
index bbc0bd1..0000000
--- a/external/badvpn_dns/client/PasswordListener.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/**
- * @file PasswordListener.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Object used to listen on a socket, accept clients and identify them
- * based on a number they send.
- */
-
-#ifndef BADVPN_CLIENT_PASSWORDLISTENER_H
-#define BADVPN_CLIENT_PASSWORDLISTENER_H
-
-#include <stdint.h>
-
-#include <prio.h>
-
-#include <cert.h>
-#include <keyhi.h>
-
-#include <misc/debug.h>
-#include <misc/sslsocket.h>
-#include <structure/LinkedList1.h>
-#include <structure/BAVL.h>
-#include <base/DebugObject.h>
-#include <flow/SingleStreamReceiver.h>
-#include <system/BConnection.h>
-#include <nspr_support/BSSLConnection.h>
-
-/**
- * Handler function called when a client identifies itself with a password
- * belonging to one of the password entries.
- * The password entry is unregistered before the handler is called
- * and must not be unregistered again.
- * 
- * @param user as in {@link PasswordListener_AddEntry}
- * @param sock structure containing a {@link BConnection} and, if TLS is enabled,
- *             the SSL socket with the bottom layer connected to the async interfaces
- *             of the {@link BConnection} object. The structure was allocated with
- *             malloc() and the user is responsible for freeing it.
- */
-typedef void (*PasswordListener_handler_client) (void *user, sslsocket *sock);
-
-struct PasswordListenerClient;
-
-/**
- * Object used to listen on a socket, accept clients and identify them
- * based on a number they send.
- */
-typedef struct {
-    BReactor *bsys;
-    BThreadWorkDispatcher *twd;
-    int ssl;
-    int ssl_flags;
-    PRFileDesc model_dprfd;
-    PRFileDesc *model_prfd;
-    struct PasswordListenerClient *clients_data;
-    LinkedList1 clients_free;
-    LinkedList1 clients_used;
-    BAVL passwords;
-    BListener listener;
-    DebugObject d_obj;
-} PasswordListener;
-
-typedef struct {
-    uint64_t password;
-    BAVLNode tree_node;
-    PasswordListener_handler_client handler_client;
-    void *user;
-} PasswordListener_pwentry;
-
-struct PasswordListenerClient {
-    PasswordListener *l;
-    LinkedList1Node list_node;
-    sslsocket *sock;
-    BSSLConnection sslcon;
-    SingleStreamReceiver receiver;
-    uint64_t recv_buffer;
-};
-
-/**
- * Initializes the object.
- * 
- * @param l the object
- * @param bsys reactor we live in
- * @param twd thread work dispatcher. May be NULL if ssl_flags does not request performing SSL
- *            operations in threads.
- * @param listen_addr address to listen on. Must be supported according to {@link BConnection_AddressSupported}.
- * @param max_clients maximum number of client to hold until they are identified.
- *                    Must be >0.
- * @param ssl whether to use TLS. Must be 1 or 0.
- * @param ssl_flags flags passed down to {@link BSSLConnection_MakeBackend}. May be used to
- *                  request performing SSL operations in threads.
- * @param cert if using TLS, the server certificate
- * @param key if using TLS, the private key
- * @return 1 on success, 0 on failure
- */
-int PasswordListener_Init (PasswordListener *l, BReactor *bsys, BThreadWorkDispatcher *twd, BAddr listen_addr, int max_clients, int ssl, int ssl_flags, CERTCertificate *cert, SECKEYPrivateKey *key) WARN_UNUSED;
-
-/**
- * Frees the object.
- * 
- * @param l the object
- */
-void PasswordListener_Free (PasswordListener *l);
-
-/**
- * Registers a password entry.
- * 
- * @param l the object
- * @param entry uninitialized entry structure
- * @param handler_client handler function to call when a client identifies
- *                       with the password which this function returns
- * @param user value to pass to handler function
- * @return password which a client should send to be recognized and
- *         dispatched to the handler function. Should be treated as a numeric
- *         value, which a client should as a little-endian 64-bit unsigned integer
- *         when it connects.
- */
-uint64_t PasswordListener_AddEntry (PasswordListener *l, PasswordListener_pwentry *entry, PasswordListener_handler_client handler_client, void *user);
-
-/**
- * Unregisters a password entry.
- * Note that when a client is dispatched, its entry is unregistered
- * automatically and must not be unregistered again here.
- * 
- * @param l the object
- * @param entry entry to unregister
- */
-void PasswordListener_RemoveEntry (PasswordListener *l, PasswordListener_pwentry *entry);
-
-#endif
diff --git a/external/badvpn_dns/client/PeerChat.c b/external/badvpn_dns/client/PeerChat.c
deleted file mode 100644
index d9dd966..0000000
--- a/external/badvpn_dns/client/PeerChat.c
+++ /dev/null
@@ -1,433 +0,0 @@
-/**
- * @file PeerChat.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-
-#include <ssl.h>
-#include <sslerr.h>
-
-#include <misc/byteorder.h>
-#include <security/BRandom.h>
-
-#include "PeerChat.h"
-
-#include <generated/blog_channel_PeerChat.h>
-
-#define PeerLog(_o, ...) BLog_LogViaFunc((_o)->logfunc, (_o)->user, BLOG_CURRENT_CHANNEL, __VA_ARGS__)
-
-static void report_error (PeerChat *o)
-{
-    DebugError_AssertNoError(&o->d_err);
-    
-    DEBUGERROR(&o->d_err, o->handler_error(o->user))
-    return;
-}
-
-static void recv_job_handler (PeerChat *o)
-{
-    DebugObject_Access(&o->d_obj);
-    DebugError_AssertNoError(&o->d_err);
-    ASSERT(o->recv_data_len >= 0)
-    ASSERT(o->recv_data_len <= SC_MAX_MSGLEN)
-    
-    int data_len = o->recv_data_len;
-    
-    // set no received data
-    o->recv_data_len = -1;
-    
-#ifdef PEERCHAT_SIMULATE_ERROR
-    uint8_t x;
-    BRandom_randomize(&x, sizeof(x));
-    if (x < PEERCHAT_SIMULATE_ERROR) {
-        PeerLog(o, BLOG_ERROR, "simulate error");
-        report_error(o);
-        return;
-    }
-#endif
-    
-    if (o->ssl_mode != PEERCHAT_SSL_NONE) {
-        // buffer data
-        if (!SimpleStreamBuffer_Write(&o->ssl_recv_buf, o->recv_data, data_len)) {
-            PeerLog(o, BLOG_ERROR, "out of recv buffer");
-            report_error(o);
-            return;
-        }
-    } else {
-        // call message handler
-        o->handler_message(o->user, o->recv_data, data_len);
-        return;
-    }
-}
-
-static void ssl_con_handler (PeerChat *o, int event)
-{
-    DebugObject_Access(&o->d_obj);
-    DebugError_AssertNoError(&o->d_err);
-    ASSERT(o->ssl_mode == PEERCHAT_SSL_CLIENT || o->ssl_mode == PEERCHAT_SSL_SERVER)
-    ASSERT(event == BSSLCONNECTION_EVENT_ERROR)
-    
-    PeerLog(o, BLOG_ERROR, "SSL error");
-    
-    report_error(o);
-    return;
-}
-
-static SECStatus client_auth_data_callback (PeerChat *o, PRFileDesc *fd, CERTDistNames *caNames, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->ssl_mode == PEERCHAT_SSL_CLIENT)
-    
-    CERTCertificate *cert = CERT_DupCertificate(o->ssl_cert);
-    if (!cert) {
-        PeerLog(o, BLOG_ERROR, "CERT_DupCertificate failed");
-        goto fail0;
-    }
-    
-    SECKEYPrivateKey *key = SECKEY_CopyPrivateKey(o->ssl_key);
-    if (!key) {
-        PeerLog(o, BLOG_ERROR, "SECKEY_CopyPrivateKey failed");
-        goto fail1;
-    }
-    
-    *pRetCert = cert;
-    *pRetKey = key;
-    return SECSuccess;
-    
-fail1:
-    CERT_DestroyCertificate(cert);
-fail0:
-    return SECFailure;
-}
-
-static SECStatus auth_certificate_callback (PeerChat *o, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->ssl_mode == PEERCHAT_SSL_CLIENT || o->ssl_mode == PEERCHAT_SSL_SERVER)
-    
-    // This callback is used to bypass checking the server's domain name, as peers
-    // don't have domain names. We byte-compare the certificate to the one reported
-    // by the server anyway.
-    
-    SECStatus ret = SECFailure;
-    
-    CERTCertificate *cert = SSL_PeerCertificate(o->ssl_prfd);
-    if (!cert) {
-        PeerLog(o, BLOG_ERROR, "SSL_PeerCertificate failed");
-        PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
-        goto fail1;
-    }
-    
-    SECCertUsage cert_usage = (o->ssl_mode == PEERCHAT_SSL_CLIENT ? certUsageSSLServer : certUsageSSLClient);
-    
-    if (CERT_VerifyCertNow(CERT_GetDefaultCertDB(), cert, PR_TRUE, cert_usage, SSL_RevealPinArg(o->ssl_prfd)) != SECSuccess) {
-        goto fail2;
-    }
-    
-    // compare to certificate provided by the server
-    SECItem der = cert->derCert;
-    if (der.len != o->ssl_peer_cert_len || memcmp(der.data, o->ssl_peer_cert, der.len)) {
-        PeerLog(o, BLOG_ERROR, "peer certificate doesn't match");
-        PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
-        goto fail2;
-    }
-    
-    ret = SECSuccess;
-    
-fail2:
-    CERT_DestroyCertificate(cert);
-fail1:
-    return ret;
-}
-
-static void ssl_recv_if_handler_send (PeerChat *o, uint8_t *data, int data_len)
-{
-    DebugObject_Access(&o->d_obj);
-    DebugError_AssertNoError(&o->d_err);
-    ASSERT(o->ssl_mode == PEERCHAT_SSL_CLIENT || o->ssl_mode == PEERCHAT_SSL_SERVER)
-    ASSERT(data_len >= 0)
-    ASSERT(data_len <= SC_MAX_MSGLEN)
-    
-    // accept packet
-    PacketPassInterface_Done(&o->ssl_recv_if);
-    
-    // call message handler
-    o->handler_message(o->user, data, data_len);
-    return;
-}
-
-static void ssl_recv_decoder_handler_error (PeerChat *o)
-{
-    DebugObject_Access(&o->d_obj);
-    DebugError_AssertNoError(&o->d_err);
-    ASSERT(o->ssl_mode == PEERCHAT_SSL_CLIENT || o->ssl_mode == PEERCHAT_SSL_SERVER)
-    
-    PeerLog(o, BLOG_ERROR, "decoder error");
-    
-    report_error(o);
-    return;
-}
-
-int PeerChat_Init (PeerChat *o, peerid_t peer_id, int ssl_mode, int ssl_flags, CERTCertificate *ssl_cert, SECKEYPrivateKey *ssl_key,
-                   uint8_t *ssl_peer_cert, int ssl_peer_cert_len, BPendingGroup *pg, BThreadWorkDispatcher *twd, void *user,
-                   BLog_logfunc logfunc,
-                   PeerChat_handler_error handler_error,
-                   PeerChat_handler_message handler_message)
-{
-    ASSERT(ssl_mode == PEERCHAT_SSL_NONE || ssl_mode == PEERCHAT_SSL_CLIENT || ssl_mode == PEERCHAT_SSL_SERVER)
-    ASSERT(ssl_mode == PEERCHAT_SSL_NONE || ssl_peer_cert_len >= 0)
-    ASSERT(logfunc)
-    ASSERT(handler_error)
-    ASSERT(handler_message)
-    
-    // init arguments
-    o->ssl_mode = ssl_mode;
-    o->ssl_cert = ssl_cert;
-    o->ssl_key = ssl_key;
-    o->ssl_peer_cert = ssl_peer_cert;
-    o->ssl_peer_cert_len = ssl_peer_cert_len;
-    o->user = user;
-    o->logfunc = logfunc;
-    o->handler_error = handler_error;
-    o->handler_message = handler_message;
-    
-    // init copier
-    PacketCopier_Init(&o->copier, SC_MAX_MSGLEN, pg);
-    
-    // init SC encoder
-    SCOutmsgEncoder_Init(&o->sc_encoder, peer_id, PacketCopier_GetOutput(&o->copier), pg);
-    
-    // init PacketProto encoder
-    PacketProtoEncoder_Init(&o->pp_encoder, SCOutmsgEncoder_GetOutput(&o->sc_encoder), pg);
-    
-    // init recv job
-    BPending_Init(&o->recv_job, pg, (BPending_handler)recv_job_handler, o);
-    
-    // set no received data
-    o->recv_data_len = -1;
-    
-    PacketPassInterface *send_buf_output = PacketCopier_GetInput(&o->copier);
-    
-    if (o->ssl_mode != PEERCHAT_SSL_NONE) {
-        // init receive buffer
-        if (!SimpleStreamBuffer_Init(&o->ssl_recv_buf, PEERCHAT_SSL_RECV_BUF_SIZE, pg)) {
-            PeerLog(o, BLOG_ERROR, "SimpleStreamBuffer_Init failed");
-            goto fail1;
-        }
-        
-        // init SSL StreamPacketSender
-        StreamPacketSender_Init(&o->ssl_sp_sender, send_buf_output, pg);
-        
-        // init SSL bottom prfd
-        if (!BSSLConnection_MakeBackend(&o->ssl_bottom_prfd, StreamPacketSender_GetInput(&o->ssl_sp_sender), SimpleStreamBuffer_GetOutput(&o->ssl_recv_buf), twd, ssl_flags)) {
-            PeerLog(o, BLOG_ERROR, "BSSLConnection_MakeBackend failed");
-            goto fail2;
-        }
-        
-        // init SSL prfd
-        if (!(o->ssl_prfd = SSL_ImportFD(NULL, &o->ssl_bottom_prfd))) {
-            ASSERT_FORCE(PR_Close(&o->ssl_bottom_prfd) == PR_SUCCESS)
-            PeerLog(o, BLOG_ERROR, "SSL_ImportFD failed");
-            goto fail2;
-        }
-        
-        // set client or server mode
-        if (SSL_ResetHandshake(o->ssl_prfd, (o->ssl_mode == PEERCHAT_SSL_SERVER ? PR_TRUE : PR_FALSE)) != SECSuccess) {
-            PeerLog(o, BLOG_ERROR, "SSL_ResetHandshake failed");
-            goto fail3;
-        }
-        
-        if (o->ssl_mode == PEERCHAT_SSL_SERVER) {
-            // set server certificate
-            if (SSL_ConfigSecureServer(o->ssl_prfd, o->ssl_cert, o->ssl_key, NSS_FindCertKEAType(o->ssl_cert)) != SECSuccess) {
-                PeerLog(o, BLOG_ERROR, "SSL_ConfigSecureServer failed");
-                goto fail3;
-            }
-            
-            // set require client certificate
-            if (SSL_OptionSet(o->ssl_prfd, SSL_REQUEST_CERTIFICATE, PR_TRUE) != SECSuccess) {
-                PeerLog(o, BLOG_ERROR, "SSL_OptionSet(SSL_REQUEST_CERTIFICATE) failed");
-                goto fail3;
-            }
-            if (SSL_OptionSet(o->ssl_prfd, SSL_REQUIRE_CERTIFICATE, PR_TRUE) != SECSuccess) {
-                PeerLog(o, BLOG_ERROR, "SSL_OptionSet(SSL_REQUIRE_CERTIFICATE) failed");
-                goto fail3;
-            }
-        } else {
-            // set client certificate callback
-            if (SSL_GetClientAuthDataHook(o->ssl_prfd, (SSLGetClientAuthData)client_auth_data_callback, o) != SECSuccess) {
-                PeerLog(o, BLOG_ERROR, "SSL_GetClientAuthDataHook failed");
-                goto fail3;
-            }
-        }
-        
-        // set verify peer certificate hook
-        if (SSL_AuthCertificateHook(o->ssl_prfd, (SSLAuthCertificate)auth_certificate_callback, o) != SECSuccess) {
-            PeerLog(o, BLOG_ERROR, "SSL_AuthCertificateHook failed");
-            goto fail3;
-        }
-        
-        // init SSL connection
-        BSSLConnection_Init(&o->ssl_con, o->ssl_prfd, 0, pg, o, (BSSLConnection_handler)ssl_con_handler);
-        
-        // init SSL PacketStreamSender
-        PacketStreamSender_Init(&o->ssl_ps_sender, BSSLConnection_GetSendIf(&o->ssl_con), sizeof(struct packetproto_header) + SC_MAX_MSGLEN, pg);
-        
-        // init SSL copier
-        PacketCopier_Init(&o->ssl_copier, SC_MAX_MSGLEN, pg);
-        
-        // init SSL encoder
-        PacketProtoEncoder_Init(&o->ssl_encoder, PacketCopier_GetOutput(&o->ssl_copier), pg);
-        
-        // init SSL buffer
-        if (!SinglePacketBuffer_Init(&o->ssl_buffer, PacketProtoEncoder_GetOutput(&o->ssl_encoder), PacketStreamSender_GetInput(&o->ssl_ps_sender), pg)) {
-            PeerLog(o, BLOG_ERROR, "SinglePacketBuffer_Init failed");
-            goto fail4;
-        }
-        
-        // init receive interface
-        PacketPassInterface_Init(&o->ssl_recv_if, SC_MAX_MSGLEN, (PacketPassInterface_handler_send)ssl_recv_if_handler_send, o, pg);
-        
-        // init receive decoder
-        if (!PacketProtoDecoder_Init(&o->ssl_recv_decoder, BSSLConnection_GetRecvIf(&o->ssl_con), &o->ssl_recv_if, pg, o, (PacketProtoDecoder_handler_error)ssl_recv_decoder_handler_error)) {
-            PeerLog(o, BLOG_ERROR, "PacketProtoDecoder_Init failed");
-            goto fail5;
-        }
-        
-        send_buf_output = PacketCopier_GetInput(&o->ssl_copier);
-    }
-    
-    // init send writer
-    BufferWriter_Init(&o->send_writer, SC_MAX_MSGLEN, pg);
-    
-    // init send buffer
-    if (!PacketBuffer_Init(&o->send_buf, BufferWriter_GetOutput(&o->send_writer), send_buf_output, PEERCHAT_SEND_BUF_SIZE, pg)) {
-        PeerLog(o, BLOG_ERROR, "PacketBuffer_Init failed");
-        goto fail6;
-    }
-    
-    DebugError_Init(&o->d_err, pg);
-    DebugObject_Init(&o->d_obj);
-    return 1;
-    
-fail6:
-    BufferWriter_Free(&o->send_writer);
-    if (o->ssl_mode != PEERCHAT_SSL_NONE) {
-        PacketProtoDecoder_Free(&o->ssl_recv_decoder);
-fail5:
-        PacketPassInterface_Free(&o->ssl_recv_if);
-        SinglePacketBuffer_Free(&o->ssl_buffer);
-fail4:
-        PacketProtoEncoder_Free(&o->ssl_encoder);
-        PacketCopier_Free(&o->ssl_copier);
-        PacketStreamSender_Free(&o->ssl_ps_sender);
-        BSSLConnection_Free(&o->ssl_con);
-fail3:
-        ASSERT_FORCE(PR_Close(o->ssl_prfd) == PR_SUCCESS)
-fail2:
-        StreamPacketSender_Free(&o->ssl_sp_sender);
-        SimpleStreamBuffer_Free(&o->ssl_recv_buf);
-    }
-fail1:
-    BPending_Free(&o->recv_job);
-    PacketProtoEncoder_Free(&o->pp_encoder);
-    SCOutmsgEncoder_Free(&o->sc_encoder);
-    PacketCopier_Free(&o->copier);
-    return 0;
-}
-
-void PeerChat_Free (PeerChat *o)
-{
-    DebugObject_Free(&o->d_obj);
-    DebugError_Free(&o->d_err);
-    
-    // stop using any buffers before they get freed
-    if (o->ssl_mode != PEERCHAT_SSL_NONE) {
-        BSSLConnection_ReleaseBuffers(&o->ssl_con);
-    }
-    
-    PacketBuffer_Free(&o->send_buf);
-    BufferWriter_Free(&o->send_writer);
-    if (o->ssl_mode != PEERCHAT_SSL_NONE) {
-        PacketProtoDecoder_Free(&o->ssl_recv_decoder);
-        PacketPassInterface_Free(&o->ssl_recv_if);
-        SinglePacketBuffer_Free(&o->ssl_buffer);
-        PacketProtoEncoder_Free(&o->ssl_encoder);
-        PacketCopier_Free(&o->ssl_copier);
-        PacketStreamSender_Free(&o->ssl_ps_sender);
-        BSSLConnection_Free(&o->ssl_con);
-        ASSERT_FORCE(PR_Close(o->ssl_prfd) == PR_SUCCESS)
-        StreamPacketSender_Free(&o->ssl_sp_sender);
-        SimpleStreamBuffer_Free(&o->ssl_recv_buf);
-    }
-    BPending_Free(&o->recv_job);
-    PacketProtoEncoder_Free(&o->pp_encoder);
-    SCOutmsgEncoder_Free(&o->sc_encoder);
-    PacketCopier_Free(&o->copier);
-}
-
-PacketRecvInterface * PeerChat_GetSendOutput (PeerChat *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return PacketProtoEncoder_GetOutput(&o->pp_encoder);
-}
-
-void PeerChat_InputReceived (PeerChat *o, uint8_t *data, int data_len)
-{
-    DebugObject_Access(&o->d_obj);
-    DebugError_AssertNoError(&o->d_err);
-    ASSERT(o->recv_data_len == -1)
-    ASSERT(data_len >= 0)
-    ASSERT(data_len <= SC_MAX_MSGLEN)
-    
-    // remember data
-    o->recv_data = data;
-    o->recv_data_len = data_len;
-    
-    // set received job
-    BPending_Set(&o->recv_job);
-}
-
-int PeerChat_StartMessage (PeerChat *o, uint8_t **data)
-{
-    DebugObject_Access(&o->d_obj);
-    DebugError_AssertNoError(&o->d_err);
-    
-    return BufferWriter_StartPacket(&o->send_writer, data);
-}
-
-void PeerChat_EndMessage (PeerChat *o, int data_len)
-{
-    DebugObject_Access(&o->d_obj);
-    DebugError_AssertNoError(&o->d_err);
-    ASSERT(data_len >= 0)
-    ASSERT(data_len <= SC_MAX_MSGLEN)
-    
-    BufferWriter_EndPacket(&o->send_writer, data_len);
-}
diff --git a/external/badvpn_dns/client/PeerChat.h b/external/badvpn_dns/client/PeerChat.h
deleted file mode 100644
index 674e374..0000000
--- a/external/badvpn_dns/client/PeerChat.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * @file PeerChat.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BADVPN_PEERCHAT_H
-#define BADVPN_PEERCHAT_H
-
-#include <cert.h>
-#include <keyhi.h>
-
-#include <protocol/packetproto.h>
-#include <protocol/scproto.h>
-#include <misc/debug.h>
-#include <misc/debugerror.h>
-#include <base/DebugObject.h>
-#include <base/BPending.h>
-#include <base/BLog.h>
-#include <flow/SinglePacketSender.h>
-#include <flow/PacketProtoEncoder.h>
-#include <flow/PacketCopier.h>
-#include <flow/StreamPacketSender.h>
-#include <flow/PacketStreamSender.h>
-#include <flow/SinglePacketBuffer.h>
-#include <flow/PacketProtoDecoder.h>
-#include <flow/PacketBuffer.h>
-#include <flow/BufferWriter.h>
-#include <nspr_support/BSSLConnection.h>
-#include <client/SCOutmsgEncoder.h>
-#include <client/SimpleStreamBuffer.h>
-
-#define PEERCHAT_SSL_NONE 0
-#define PEERCHAT_SSL_CLIENT 1
-#define PEERCHAT_SSL_SERVER 2
-
-#define PEERCHAT_SSL_RECV_BUF_SIZE 4096
-#define PEERCHAT_SEND_BUF_SIZE 200
-
-//#define PEERCHAT_SIMULATE_ERROR 40
-
-typedef void (*PeerChat_handler_error) (void *user);
-typedef void (*PeerChat_handler_message) (void *user, uint8_t *data, int data_len);
-
-typedef struct {
-    int ssl_mode;
-    CERTCertificate *ssl_cert;
-    SECKEYPrivateKey *ssl_key;
-    uint8_t *ssl_peer_cert;
-    int ssl_peer_cert_len;
-    void *user;
-    BLog_logfunc logfunc;
-    PeerChat_handler_error handler_error;
-    PeerChat_handler_message handler_message;
-    
-    // transport
-    PacketProtoEncoder pp_encoder;
-    SCOutmsgEncoder sc_encoder;
-    PacketCopier copier;
-    BPending recv_job;
-    uint8_t *recv_data;
-    int recv_data_len;
-    
-    // SSL transport
-    StreamPacketSender ssl_sp_sender;
-    SimpleStreamBuffer ssl_recv_buf;
-    
-    // SSL connection
-    PRFileDesc ssl_bottom_prfd;
-    PRFileDesc *ssl_prfd;
-    BSSLConnection ssl_con;
-    
-    // SSL higher layer
-    PacketStreamSender ssl_ps_sender;
-    SinglePacketBuffer ssl_buffer;
-    PacketProtoEncoder ssl_encoder;
-    PacketCopier ssl_copier;
-    PacketProtoDecoder ssl_recv_decoder;
-    PacketPassInterface ssl_recv_if;
-    
-    // higher layer send buffer
-    PacketBuffer send_buf;
-    BufferWriter send_writer;
-    
-    DebugError d_err;
-    DebugObject d_obj;
-} PeerChat;
-
-int PeerChat_Init (PeerChat *o, peerid_t peer_id, int ssl_mode, int ssl_flags, CERTCertificate *ssl_cert, SECKEYPrivateKey *ssl_key,
-                   uint8_t *ssl_peer_cert, int ssl_peer_cert_len, BPendingGroup *pg, BThreadWorkDispatcher *twd, void *user,
-                   BLog_logfunc logfunc,
-                   PeerChat_handler_error handler_error,
-                   PeerChat_handler_message handler_message) WARN_UNUSED;
-void PeerChat_Free (PeerChat *o);
-PacketRecvInterface * PeerChat_GetSendOutput (PeerChat *o);
-void PeerChat_InputReceived (PeerChat *o, uint8_t *data, int data_len);
-int PeerChat_StartMessage (PeerChat *o, uint8_t **data) WARN_UNUSED;
-void PeerChat_EndMessage (PeerChat *o, int data_len);
-
-#endif
diff --git a/external/badvpn_dns/client/SCOutmsgEncoder.c b/external/badvpn_dns/client/SCOutmsgEncoder.c
deleted file mode 100644
index 83e8b27..0000000
--- a/external/badvpn_dns/client/SCOutmsgEncoder.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * @file SCOutmsgEncoder.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stddef.h>
-#include <limits.h>
-#include <string.h>
-
-#include <misc/balign.h>
-#include <misc/debug.h>
-#include <misc/byteorder.h>
-
-#include "SCOutmsgEncoder.h"
-
-static void output_handler_recv (SCOutmsgEncoder *o, uint8_t *data)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(!o->output_packet)
-    ASSERT(data)
-    
-    // schedule receive
-    o->output_packet = data;
-    PacketRecvInterface_Receiver_Recv(o->input, o->output_packet + SCOUTMSG_OVERHEAD);
-}
-
-static void input_handler_done (SCOutmsgEncoder *o, int in_len)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->output_packet)
-    
-    // write SC header
-    struct sc_header header;
-    header.type = htol8(SCID_OUTMSG);
-    memcpy(o->output_packet, &header, sizeof(header));
-    
-    // write outmsg
-    struct sc_client_outmsg outmsg;
-    outmsg.clientid = htol16(o->peer_id);
-    memcpy(o->output_packet + sizeof(header), &outmsg, sizeof(outmsg));
-    
-    // finish output packet
-    o->output_packet = NULL;
-    PacketRecvInterface_Done(&o->output, SCOUTMSG_OVERHEAD + in_len);
-}
-
-void SCOutmsgEncoder_Init (SCOutmsgEncoder *o, peerid_t peer_id, PacketRecvInterface *input, BPendingGroup *pg)
-{
-    ASSERT(PacketRecvInterface_GetMTU(input) <= INT_MAX - SCOUTMSG_OVERHEAD)
-    
-    // init arguments
-    o->peer_id = peer_id;
-    o->input = input;
-    
-    // init input
-    PacketRecvInterface_Receiver_Init(o->input, (PacketRecvInterface_handler_done)input_handler_done, o);
-    
-    // init output
-    PacketRecvInterface_Init(&o->output, SCOUTMSG_OVERHEAD + PacketRecvInterface_GetMTU(o->input), (PacketRecvInterface_handler_recv)output_handler_recv, o, pg);
-    
-    // set no output packet
-    o->output_packet = NULL;
-    
-    DebugObject_Init(&o->d_obj);
-}
-
-void SCOutmsgEncoder_Free (SCOutmsgEncoder *o)
-{
-    DebugObject_Free(&o->d_obj);
-
-    // free input
-    PacketRecvInterface_Free(&o->output);
-}
-
-PacketRecvInterface * SCOutmsgEncoder_GetOutput (SCOutmsgEncoder *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->output;
-}
diff --git a/external/badvpn_dns/client/SCOutmsgEncoder.h b/external/badvpn_dns/client/SCOutmsgEncoder.h
deleted file mode 100644
index 05d4cb2..0000000
--- a/external/badvpn_dns/client/SCOutmsgEncoder.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * @file SCOutmsgEncoder.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BADVPN_SCOUTMSGENCODER_H
-#define BADVPN_SCOUTMSGENCODER_H
-
-#include <protocol/scproto.h>
-#include <base/DebugObject.h>
-#include <flow/PacketRecvInterface.h>
-
-#define SCOUTMSG_OVERHEAD (sizeof(struct sc_header) + sizeof(struct sc_client_outmsg))
-
-/**
- * A {@link PacketRecvInterface} layer which encodes SCProto outgoing messages.
- */
-typedef struct {
-    peerid_t peer_id;
-    PacketRecvInterface *input;
-    PacketRecvInterface output;
-    uint8_t *output_packet;
-    DebugObject d_obj;
-} SCOutmsgEncoder;
-
-/**
- * Initializes the object.
- * 
- * @param o the object
- * @param peer_id destination peer for messages
- * @param input input interface. Its MTU muse be <= (INT_MAX - SCOUTMSG_OVERHEAD).
- * @param pg pending group we live in
- */
-void SCOutmsgEncoder_Init (SCOutmsgEncoder *o, peerid_t peer_id, PacketRecvInterface *input, BPendingGroup *pg);
-
-/**
- * Frees the object.
- * 
- * @param o the object
- */
-void SCOutmsgEncoder_Free (SCOutmsgEncoder *o);
-
-/**
- * Returns the output interface.
- * The MTU of the interface will be (SCOUTMSG_OVERHEAD + input MTU).
- * 
- * @param o the object
- * @return output interface
- */
-PacketRecvInterface * SCOutmsgEncoder_GetOutput (SCOutmsgEncoder *o);
-
-#endif
diff --git a/external/badvpn_dns/client/SPProtoDecoder.c b/external/badvpn_dns/client/SPProtoDecoder.c
deleted file mode 100644
index 0855162..0000000
--- a/external/badvpn_dns/client/SPProtoDecoder.c
+++ /dev/null
@@ -1,398 +0,0 @@
-/**
- * @file SPProtoDecoder.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-
-#include <misc/balign.h>
-#include <misc/byteorder.h>
-#include <security/BHash.h>
-
-#include "SPProtoDecoder.h"
-
-#include <generated/blog_channel_SPProtoDecoder.h>
-
-#define PeerLog(_o, ...) BLog_LogViaFunc((_o)->logfunc, (_o)->user, BLOG_CURRENT_CHANNEL, __VA_ARGS__)
-
-static void decode_work_func (SPProtoDecoder *o)
-{
-    ASSERT(o->in_len >= 0)
-    ASSERT(o->in_len <= o->input_mtu)
-    
-    uint8_t *in = o->in;
-    int in_len = o->in_len;
-    
-    o->tw_out_len = -1;
-    
-    uint8_t *plaintext;
-    int plaintext_len;
-    
-    // decrypt if needed
-    if (!SPPROTO_HAVE_ENCRYPTION(o->sp_params)) {
-        plaintext = in;
-        plaintext_len = in_len;
-    } else {
-        // input must be a multiple of blocks size
-        if (in_len % o->enc_block_size != 0) {
-            PeerLog(o, BLOG_WARNING, "packet size not a multiple of block size");
-            return;
-        }
-        
-        // input must have an IV block
-        if (in_len < o->enc_block_size) {
-            PeerLog(o, BLOG_WARNING, "packet does not have an IV");
-            return;
-        }
-        
-        // check if we have encryption key
-        if (!o->have_encryption_key) {
-            PeerLog(o, BLOG_WARNING, "have no encryption key");
-            return;
-        }
-        
-        // copy IV as BEncryption_Decrypt changes the IV
-        uint8_t iv[BENCRYPTION_MAX_BLOCK_SIZE];
-        memcpy(iv, in, o->enc_block_size);
-        
-        // decrypt
-        uint8_t *ciphertext = in + o->enc_block_size;
-        int ciphertext_len = in_len - o->enc_block_size;
-        plaintext = o->buf;
-        BEncryption_Decrypt(&o->encryptor, ciphertext, plaintext, ciphertext_len, iv);
-        
-        // read padding
-        if (ciphertext_len < o->enc_block_size) {
-            PeerLog(o, BLOG_WARNING, "packet does not have a padding block");
-            return;
-        }
-        int i;
-        for (i = ciphertext_len - 1; i >= ciphertext_len - o->enc_block_size; i--) {
-            if (plaintext[i] == 1) {
-                break;
-            }
-            if (plaintext[i] != 0) {
-                PeerLog(o, BLOG_WARNING, "packet padding wrong (nonzero byte)");
-                return;
-            }
-        }
-        if (i < ciphertext_len - o->enc_block_size) {
-            PeerLog(o, BLOG_WARNING, "packet padding wrong (all zeroes)");
-            return;
-        }
-        plaintext_len = i;
-    }
-    
-    // check for header
-    if (plaintext_len < SPPROTO_HEADER_LEN(o->sp_params)) {
-        PeerLog(o, BLOG_WARNING, "packet has no header");
-        return;
-    }
-    uint8_t *header = plaintext;
-    
-    // check data length
-    if (plaintext_len - SPPROTO_HEADER_LEN(o->sp_params) > o->output_mtu) {
-        PeerLog(o, BLOG_WARNING, "packet too long");
-        return;
-    }
-    
-    // check OTP
-    if (SPPROTO_HAVE_OTP(o->sp_params)) {
-        // remember seed and OTP (can't check from here)
-        struct spproto_otpdata header_otpd;
-        memcpy(&header_otpd, header + SPPROTO_HEADER_OTPDATA_OFF(o->sp_params), sizeof(header_otpd));
-        o->tw_out_seed_id = ltoh16(header_otpd.seed_id);
-        o->tw_out_otp = header_otpd.otp;
-    }
-    
-    // check hash
-    if (SPPROTO_HAVE_HASH(o->sp_params)) {
-        uint8_t *header_hash = header + SPPROTO_HEADER_HASH_OFF(o->sp_params);
-        // read hash
-        uint8_t hash[BHASH_MAX_SIZE];
-        memcpy(hash, header_hash, o->hash_size);
-        // zero hash in packet
-        memset(header_hash, 0, o->hash_size);
-        // calculate hash
-        uint8_t hash_calc[BHASH_MAX_SIZE];
-        BHash_calculate(o->sp_params.hash_mode, plaintext, plaintext_len, hash_calc);
-        // set hash field to its original value
-        memcpy(header_hash, hash, o->hash_size);
-        // compare hashes
-        if (memcmp(hash, hash_calc, o->hash_size)) {
-            PeerLog(o, BLOG_WARNING, "packet has wrong hash");
-            return;
-        }
-    }
-    
-    // return packet
-    o->tw_out = plaintext + SPPROTO_HEADER_LEN(o->sp_params);
-    o->tw_out_len = plaintext_len - SPPROTO_HEADER_LEN(o->sp_params);
-}
-
-static void decode_work_handler (SPProtoDecoder *o)
-{
-    ASSERT(o->in_len >= 0)
-    ASSERT(o->tw_have)
-    DebugObject_Access(&o->d_obj);
-    
-    // free work
-    BThreadWork_Free(&o->tw);
-    o->tw_have = 0;
-    
-    // check OTP
-    if (SPPROTO_HAVE_OTP(o->sp_params) && o->tw_out_len >= 0) {
-        if (!OTPChecker_CheckOTP(&o->otpchecker, o->tw_out_seed_id, o->tw_out_otp)) {
-            PeerLog(o, BLOG_WARNING, "packet has wrong OTP");
-            o->tw_out_len = -1;
-        }
-    }
-    
-    if (o->tw_out_len < 0) {
-        // cannot decode, finish input packet
-        PacketPassInterface_Done(&o->input);
-        o->in_len = -1;
-    } else {
-        // submit decoded packet to output
-        PacketPassInterface_Sender_Send(o->output, o->tw_out, o->tw_out_len);
-    }
-}
-
-static void input_handler_send (SPProtoDecoder *o, uint8_t *data, int data_len)
-{
-    ASSERT(data_len >= 0)
-    ASSERT(data_len <= o->input_mtu)
-    ASSERT(o->in_len == -1)
-    ASSERT(!o->tw_have)
-    DebugObject_Access(&o->d_obj);
-    
-    // remember input
-    o->in = data;
-    o->in_len = data_len;
-    
-    // start decoding
-    BThreadWork_Init(&o->tw, o->twd, (BThreadWork_handler_done)decode_work_handler, o, (BThreadWork_work_func)decode_work_func, o);
-    o->tw_have = 1;
-}
-
-static void output_handler_done (SPProtoDecoder *o)
-{
-    ASSERT(o->in_len >= 0)
-    ASSERT(!o->tw_have)
-    DebugObject_Access(&o->d_obj);
-    
-    // finish input packet
-    PacketPassInterface_Done(&o->input);
-    o->in_len = -1;
-}
-
-static void maybe_stop_work_and_ignore (SPProtoDecoder *o)
-{
-    ASSERT(!(o->tw_have) || o->in_len >= 0)
-    
-    if (o->tw_have) {
-        // free work
-        BThreadWork_Free(&o->tw);
-        o->tw_have = 0;
-        
-        // ignore packet, receive next one
-        PacketPassInterface_Done(&o->input);
-        o->in_len = -1;
-    }
-}
-
-int SPProtoDecoder_Init (SPProtoDecoder *o, PacketPassInterface *output, struct spproto_security_params sp_params, int num_otp_seeds, BPendingGroup *pg, BThreadWorkDispatcher *twd, void *user, BLog_logfunc logfunc)
-{
-    spproto_assert_security_params(sp_params);
-    ASSERT(spproto_carrier_mtu_for_payload_mtu(sp_params, PacketPassInterface_GetMTU(output)) >= 0)
-    ASSERT(!SPPROTO_HAVE_OTP(sp_params) || num_otp_seeds >= 2)
-    
-    // init arguments
-    o->output = output;
-    o->sp_params = sp_params;
-    o->twd = twd;
-    o->user = user;
-    o->logfunc = logfunc;
-    
-    // init output
-    PacketPassInterface_Sender_Init(o->output, (PacketPassInterface_handler_done)output_handler_done, o);
-    
-    // remember output MTU
-    o->output_mtu = PacketPassInterface_GetMTU(o->output);
-    
-    // calculate hash size
-    if (SPPROTO_HAVE_HASH(o->sp_params)) {
-        o->hash_size = BHash_size(o->sp_params.hash_mode);
-    }
-    
-    // calculate encryption block and key sizes
-    if (SPPROTO_HAVE_ENCRYPTION(o->sp_params)) {
-        o->enc_block_size = BEncryption_cipher_block_size(o->sp_params.encryption_mode);
-        o->enc_key_size = BEncryption_cipher_key_size(o->sp_params.encryption_mode);
-    }
-    
-    // calculate input MTU
-    o->input_mtu = spproto_carrier_mtu_for_payload_mtu(o->sp_params, o->output_mtu);
-    
-    // allocate plaintext buffer
-    if (SPPROTO_HAVE_ENCRYPTION(o->sp_params)) {
-        int buf_size = balign_up((SPPROTO_HEADER_LEN(o->sp_params) + o->output_mtu + 1), o->enc_block_size);
-        if (!(o->buf = (uint8_t *)malloc(buf_size))) {
-            goto fail0;
-        }
-    }
-    
-    // init input
-    PacketPassInterface_Init(&o->input, o->input_mtu, (PacketPassInterface_handler_send)input_handler_send, o, pg);
-    
-    // init OTP checker
-    if (SPPROTO_HAVE_OTP(o->sp_params)) {
-        if (!OTPChecker_Init(&o->otpchecker, o->sp_params.otp_num, o->sp_params.otp_mode, num_otp_seeds, o->twd)) {
-            goto fail1;
-        }
-    }
-    
-    // have no encryption key
-    if (SPPROTO_HAVE_ENCRYPTION(o->sp_params)) { 
-        o->have_encryption_key = 0;
-    }
-    
-    // have no input packet
-    o->in_len = -1;
-    
-    // have no work
-    o->tw_have = 0;
-    
-    DebugObject_Init(&o->d_obj);
-    
-    return 1;
-    
-fail1:
-    PacketPassInterface_Free(&o->input);
-    if (SPPROTO_HAVE_ENCRYPTION(o->sp_params)) {
-        free(o->buf);
-    }
-fail0:
-    return 0;
-}
-
-void SPProtoDecoder_Free (SPProtoDecoder *o)
-{
-    DebugObject_Free(&o->d_obj);
-    
-    // free work
-    if (o->tw_have) {
-        BThreadWork_Free(&o->tw);
-    }
-    
-    // free encryptor
-    if (SPPROTO_HAVE_ENCRYPTION(o->sp_params) && o->have_encryption_key) {
-        BEncryption_Free(&o->encryptor);
-    }
-    
-    // free OTP checker
-    if (SPPROTO_HAVE_OTP(o->sp_params)) {
-        OTPChecker_Free(&o->otpchecker);
-    }
-    
-    // free input
-    PacketPassInterface_Free(&o->input);
-    
-    // free plaintext buffer
-    if (SPPROTO_HAVE_ENCRYPTION(o->sp_params)) {
-        free(o->buf);
-    }
-}
-
-PacketPassInterface * SPProtoDecoder_GetInput (SPProtoDecoder *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->input;
-}
-
-void SPProtoDecoder_SetEncryptionKey (SPProtoDecoder *o, uint8_t *encryption_key)
-{
-    ASSERT(SPPROTO_HAVE_ENCRYPTION(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    // stop existing work
-    maybe_stop_work_and_ignore(o);
-    
-    // free encryptor
-    if (o->have_encryption_key) {
-        BEncryption_Free(&o->encryptor);
-    }
-    
-    // init encryptor
-    BEncryption_Init(&o->encryptor, BENCRYPTION_MODE_DECRYPT, o->sp_params.encryption_mode, encryption_key);
-    
-    // have encryption key
-    o->have_encryption_key = 1;
-}
-
-void SPProtoDecoder_RemoveEncryptionKey (SPProtoDecoder *o)
-{
-    ASSERT(SPPROTO_HAVE_ENCRYPTION(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    // stop existing work
-    maybe_stop_work_and_ignore(o);
-    
-    if (o->have_encryption_key) {
-        // free encryptor
-        BEncryption_Free(&o->encryptor);
-        
-        // have no encryption key
-        o->have_encryption_key = 0;
-    }
-}
-
-void SPProtoDecoder_AddOTPSeed (SPProtoDecoder *o, uint16_t seed_id, uint8_t *key, uint8_t *iv)
-{
-    ASSERT(SPPROTO_HAVE_OTP(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    OTPChecker_AddSeed(&o->otpchecker, seed_id, key, iv);
-}
-
-void SPProtoDecoder_RemoveOTPSeeds (SPProtoDecoder *o)
-{
-    ASSERT(SPPROTO_HAVE_OTP(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    OTPChecker_RemoveSeeds(&o->otpchecker);
-}
-
-void SPProtoDecoder_SetHandlers (SPProtoDecoder *o, SPProtoDecoder_otp_handler otp_handler, void *user)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    if (SPPROTO_HAVE_OTP(o->sp_params)) {
-        OTPChecker_SetHandlers(&o->otpchecker, otp_handler, user);
-    }
-}
diff --git a/external/badvpn_dns/client/SPProtoDecoder.h b/external/badvpn_dns/client/SPProtoDecoder.h
deleted file mode 100644
index 3b5de71..0000000
--- a/external/badvpn_dns/client/SPProtoDecoder.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/**
- * @file SPProtoDecoder.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Object which decodes packets according to SPProto.
- */
-
-#ifndef BADVPN_CLIENT_SPPROTODECODER_H
-#define BADVPN_CLIENT_SPPROTODECODER_H
-
-#include <stdint.h>
-
-#include <misc/debug.h>
-#include <base/DebugObject.h>
-#include <base/BLog.h>
-#include <protocol/spproto.h>
-#include <security/BEncryption.h>
-#include <security/OTPChecker.h>
-#include <flow/PacketPassInterface.h>
-
-/**
- * Handler called when OTP generation for a new seed is finished.
- * 
- * @param user as in {@link SPProtoDecoder_Init}
- */
-typedef void (*SPProtoDecoder_otp_handler) (void *user);
-
-/**
- * Object which decodes packets according to SPProto.
- * Input is with {@link PacketPassInterface}.
- * Output is with {@link PacketPassInterface}.
- */
-typedef struct {
-    PacketPassInterface *output;
-    struct spproto_security_params sp_params;
-    BThreadWorkDispatcher *twd;
-    void *user;
-    BLog_logfunc logfunc;
-    int output_mtu;
-    int hash_size;
-    int enc_block_size;
-    int enc_key_size;
-    int input_mtu;
-    uint8_t *buf;
-    PacketPassInterface input;
-    OTPChecker otpchecker;
-    int have_encryption_key;
-    BEncryption encryptor;
-    uint8_t *in;
-    int in_len;
-    int tw_have;
-    BThreadWork tw;
-    uint16_t tw_out_seed_id;
-    otp_t tw_out_otp;
-    uint8_t *tw_out;
-    int tw_out_len;
-    DebugObject d_obj;
-} SPProtoDecoder;
-
-/**
- * Initializes the object.
- * {@link BSecurity_GlobalInitThreadSafe} must have been done if
- * {@link BThreadWorkDispatcher_UsingThreads}(twd) = 1.
- *
- * @param o the object
- * @param output output interface. Its MTU must not be too large, i.e. this must hold:
- *               spproto_carrier_mtu_for_payload_mtu(sp_params, output MTU) >= 0
- * @param sp_params SPProto parameters
- * @param encryption_key if using encryption, the encryption key
- * @param num_otp_seeds if using OTPs, how many OTP seeds to keep for checking
- *                      receiving packets. Must be >=2 if using OTPs.
- * @param pg pending group
- * @param twd thread work dispatcher
- * @param user argument to handlers
- * @param logfunc function which prepends the log prefix using {@link BLog_Append}
- * @return 1 on success, 0 on failure
- */
-int SPProtoDecoder_Init (SPProtoDecoder *o, PacketPassInterface *output, struct spproto_security_params sp_params, int num_otp_seeds, BPendingGroup *pg, BThreadWorkDispatcher *twd, void *user, BLog_logfunc logfunc) WARN_UNUSED;
-
-/**
- * Frees the object.
- *
- * @param o the object
- */
-void SPProtoDecoder_Free (SPProtoDecoder *o);
-
-/**
- * Returns the input interface.
- * The MTU of the input interface will depend on the output MTU and security parameters,
- * that is spproto_carrier_mtu_for_payload_mtu(sp_params, output MTU).
- *
- * @param o the object
- * @return input interface
- */
-PacketPassInterface * SPProtoDecoder_GetInput (SPProtoDecoder *o);
-
-/**
- * Sets an encryption key for decrypting packets.
- * Encryption must be enabled.
- *
- * @param o the object
- * @param encryption_key key to use
- */
-void SPProtoDecoder_SetEncryptionKey (SPProtoDecoder *o, uint8_t *encryption_key);
-
-/**
- * Removes an encryption key if one is configured.
- * Encryption must be enabled.
- *
- * @param o the object
- */
-void SPProtoDecoder_RemoveEncryptionKey (SPProtoDecoder *o);
-
-/**
- * Starts generating OTPs for a seed to check received packets against.
- * OTPs for this seed will not be recognized until the {@link SPProtoDecoder_otp_handler} handler
- * is called.
- * If OTPs are still being generated for the previous seed, it will be forgotten.
- * OTPs must be enabled.
- *
- * @param o the object
- * @param seed_id seed identifier
- * @param key OTP encryption key
- * @param iv OTP initialization vector
- */
-void SPProtoDecoder_AddOTPSeed (SPProtoDecoder *o, uint16_t seed_id, uint8_t *key, uint8_t *iv);
-
-/**
- * Removes all OTP seeds for checking received packets against.
- * OTPs must be enabled.
- *
- * @param o the object
- */
-void SPProtoDecoder_RemoveOTPSeeds (SPProtoDecoder *o);
-
-/**
- * Sets handlers.
- *
- * @param o the object
- * @param otp_handler handler called when OTP generation is finished
- * @param user argument to handler
- */
-void SPProtoDecoder_SetHandlers (SPProtoDecoder *o, SPProtoDecoder_otp_handler otp_handler, void *user);
-
-#endif
diff --git a/external/badvpn_dns/client/SPProtoEncoder.c b/external/badvpn_dns/client/SPProtoEncoder.c
deleted file mode 100644
index fbbab50..0000000
--- a/external/badvpn_dns/client/SPProtoEncoder.c
+++ /dev/null
@@ -1,436 +0,0 @@
-/**
- * @file SPProtoEncoder.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-#include <stdlib.h>
-
-#include <misc/balign.h>
-#include <misc/offset.h>
-#include <misc/byteorder.h>
-#include <security/BRandom.h>
-#include <security/BHash.h>
-
-#include "SPProtoEncoder.h"
-
-static int can_encode (SPProtoEncoder *o);
-static void encode_packet (SPProtoEncoder *o);
-static void encode_work_func (SPProtoEncoder *o);
-static void encode_work_handler (SPProtoEncoder *o);
-static void maybe_encode (SPProtoEncoder *o);
-static void output_handler_recv (SPProtoEncoder *o, uint8_t *data);
-static void input_handler_done (SPProtoEncoder *o, int data_len);
-static void handler_job_hander (SPProtoEncoder *o);
-static void otpgenerator_handler (SPProtoEncoder *o);
-static void maybe_stop_work (SPProtoEncoder *o);
-
-static int can_encode (SPProtoEncoder *o)
-{
-    ASSERT(o->in_len >= 0)
-    ASSERT(o->out_have)
-    ASSERT(!o->tw_have)
-    
-    return (
-        (!SPPROTO_HAVE_OTP(o->sp_params) || OTPGenerator_GetPosition(&o->otpgen) < o->sp_params.otp_num) &&
-        (!SPPROTO_HAVE_ENCRYPTION(o->sp_params) || o->have_encryption_key)
-    );
-}
-
-static void encode_packet (SPProtoEncoder *o)
-{
-    ASSERT(o->in_len >= 0)
-    ASSERT(o->out_have)
-    ASSERT(!o->tw_have)
-    ASSERT(can_encode(o))
-    
-    // generate OTP, remember seed ID
-    if (SPPROTO_HAVE_OTP(o->sp_params)) {
-        o->tw_seed_id = o->otpgen_seed_id;
-        o->tw_otp = OTPGenerator_GetOTP(&o->otpgen);
-    }
-    
-    // start work
-    BThreadWork_Init(&o->tw, o->twd, (BThreadWork_handler_done)encode_work_handler, o, (BThreadWork_work_func)encode_work_func, o);
-    o->tw_have = 1;
-    
-    // schedule OTP warning handler
-    if (SPPROTO_HAVE_OTP(o->sp_params) && OTPGenerator_GetPosition(&o->otpgen) == o->otp_warning_count) {
-        BPending_Set(&o->handler_job);
-    }
-}
-
-static void encode_work_func (SPProtoEncoder *o)
-{
-    ASSERT(o->in_len >= 0)
-    ASSERT(o->out_have)
-    ASSERT(!SPPROTO_HAVE_ENCRYPTION(o->sp_params) || o->have_encryption_key)
-    
-    ASSERT(o->in_len <= o->input_mtu)
-    
-    // determine plaintext location
-    uint8_t *plaintext = (SPPROTO_HAVE_ENCRYPTION(o->sp_params) ? o->buf : o->out);
-    
-    // plaintext begins with header
-    uint8_t *header = plaintext;
-    
-    // plaintext is header + payload
-    int plaintext_len = SPPROTO_HEADER_LEN(o->sp_params) + o->in_len;
-    
-    // write OTP
-    if (SPPROTO_HAVE_OTP(o->sp_params)) {
-        struct spproto_otpdata header_otpd;
-        header_otpd.seed_id = htol16(o->tw_seed_id);
-        header_otpd.otp = o->tw_otp;
-        memcpy(header + SPPROTO_HEADER_OTPDATA_OFF(o->sp_params), &header_otpd, sizeof(header_otpd));
-    }
-    
-    // write hash
-    if (SPPROTO_HAVE_HASH(o->sp_params)) {
-        uint8_t *header_hash = header + SPPROTO_HEADER_HASH_OFF(o->sp_params);
-        // zero hash field
-        memset(header_hash, 0, o->hash_size);
-        // calculate hash
-        uint8_t hash[BHASH_MAX_SIZE];
-        BHash_calculate(o->sp_params.hash_mode, plaintext, plaintext_len, hash);
-        // set hash field
-        memcpy(header_hash, hash, o->hash_size);
-    }
-    
-    int out_len;
-    
-    if (SPPROTO_HAVE_ENCRYPTION(o->sp_params)) {
-        // encrypting pad(header + payload)
-        int cyphertext_len = balign_up((plaintext_len + 1), o->enc_block_size);
-        
-        // write padding
-        plaintext[plaintext_len] = 1;
-        for (int i = plaintext_len + 1; i < cyphertext_len; i++) {
-            plaintext[i] = 0;
-        }
-        
-        // generate IV
-        BRandom_randomize(o->out, o->enc_block_size);
-        
-        // copy IV because BEncryption_Encrypt changes the IV
-        uint8_t iv[BENCRYPTION_MAX_BLOCK_SIZE];
-        memcpy(iv, o->out, o->enc_block_size);
-        
-        // encrypt
-        BEncryption_Encrypt(&o->encryptor, plaintext, o->out + o->enc_block_size, cyphertext_len, iv);
-        out_len = o->enc_block_size + cyphertext_len;
-    } else {
-        out_len = plaintext_len;
-    }
-    
-    // remember length
-    o->tw_out_len = out_len;
-}
-
-static void encode_work_handler (SPProtoEncoder *o)
-{
-    ASSERT(o->in_len >= 0)
-    ASSERT(o->out_have)
-    ASSERT(o->tw_have)
-    
-    // free work
-    BThreadWork_Free(&o->tw);
-    o->tw_have = 0;
-    
-    // finish packet
-    o->in_len = -1;
-    o->out_have = 0;
-    PacketRecvInterface_Done(&o->output, o->tw_out_len);
-}
-
-static void maybe_encode (SPProtoEncoder *o)
-{
-    if (o->in_len >= 0 && o->out_have && !o->tw_have && can_encode(o)) {
-        encode_packet(o);
-    }
-}
-
-static void output_handler_recv (SPProtoEncoder *o, uint8_t *data)
-{
-    ASSERT(o->in_len == -1)
-    ASSERT(!o->out_have)
-    ASSERT(!o->tw_have)
-    DebugObject_Access(&o->d_obj);
-    
-    // remember output packet
-    o->out_have = 1;
-    o->out = data;
-    
-    // determine plaintext location
-    uint8_t *plaintext = (SPPROTO_HAVE_ENCRYPTION(o->sp_params) ? o->buf : o->out);
-    
-    // schedule receive
-    PacketRecvInterface_Receiver_Recv(o->input, plaintext + SPPROTO_HEADER_LEN(o->sp_params));
-}
-
-static void input_handler_done (SPProtoEncoder *o, int data_len)
-{
-    ASSERT(data_len >= 0)
-    ASSERT(data_len <= o->input_mtu)
-    ASSERT(o->in_len == -1)
-    ASSERT(o->out_have)
-    ASSERT(!o->tw_have)
-    DebugObject_Access(&o->d_obj);
-    
-    // remember input packet
-    o->in_len = data_len;
-    
-    // encode if possible
-    if (can_encode(o)) {
-        encode_packet(o);
-    }
-}
-
-static void handler_job_hander (SPProtoEncoder *o)
-{
-    ASSERT(SPPROTO_HAVE_OTP(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    if (o->handler) {
-        o->handler(o->user);
-        return;
-    }
-}
-
-static void otpgenerator_handler (SPProtoEncoder *o)
-{
-    ASSERT(SPPROTO_HAVE_OTP(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    // remember seed ID
-    o->otpgen_seed_id = o->otpgen_pending_seed_id;
-    
-    // possibly continue I/O
-    maybe_encode(o);
-}
-
-static void maybe_stop_work (SPProtoEncoder *o)
-{
-    // stop existing work
-    if (o->tw_have) {
-        BThreadWork_Free(&o->tw);
-        o->tw_have = 0;
-    }
-}
-
-int SPProtoEncoder_Init (SPProtoEncoder *o, PacketRecvInterface *input, struct spproto_security_params sp_params, int otp_warning_count, BPendingGroup *pg, BThreadWorkDispatcher *twd)
-{
-    spproto_assert_security_params(sp_params);
-    ASSERT(spproto_carrier_mtu_for_payload_mtu(sp_params, PacketRecvInterface_GetMTU(input)) >= 0)
-    if (SPPROTO_HAVE_OTP(sp_params)) {
-        ASSERT(otp_warning_count > 0)
-        ASSERT(otp_warning_count <= sp_params.otp_num)
-    }
-    
-    // init arguments
-    o->input = input;
-    o->sp_params = sp_params;
-    o->otp_warning_count = otp_warning_count;
-    o->twd = twd;
-    
-    // set no handlers
-    o->handler = NULL;
-    
-    // calculate hash size
-    if (SPPROTO_HAVE_HASH(o->sp_params)) {
-        o->hash_size = BHash_size(o->sp_params.hash_mode);
-    }
-    
-    // calculate encryption block and key sizes
-    if (SPPROTO_HAVE_ENCRYPTION(o->sp_params)) {
-        o->enc_block_size = BEncryption_cipher_block_size(o->sp_params.encryption_mode);
-        o->enc_key_size = BEncryption_cipher_key_size(o->sp_params.encryption_mode);
-    }
-    
-    // init otp generator
-    if (SPPROTO_HAVE_OTP(o->sp_params)) {
-        if (!OTPGenerator_Init(&o->otpgen, o->sp_params.otp_num, o->sp_params.otp_mode, o->twd, (OTPGenerator_handler)otpgenerator_handler, o)) {
-            goto fail0;
-        }
-    }
-    
-    // have no encryption key
-    if (SPPROTO_HAVE_ENCRYPTION(o->sp_params)) { 
-        o->have_encryption_key = 0;
-    }
-    
-    // remember input MTU
-    o->input_mtu = PacketRecvInterface_GetMTU(o->input);
-    
-    // calculate output MTU
-    o->output_mtu = spproto_carrier_mtu_for_payload_mtu(o->sp_params, o->input_mtu);
-    
-    // init input
-    PacketRecvInterface_Receiver_Init(o->input, (PacketRecvInterface_handler_done)input_handler_done, o);
-    
-    // have no input in buffer
-    o->in_len = -1;
-    
-    // init output
-    PacketRecvInterface_Init(&o->output, o->output_mtu, (PacketRecvInterface_handler_recv)output_handler_recv, o, pg);
-    
-    // have no output available
-    o->out_have = 0;
-    
-    // allocate plaintext buffer
-    if (SPPROTO_HAVE_ENCRYPTION(o->sp_params)) {
-        int buf_size = balign_up((SPPROTO_HEADER_LEN(o->sp_params) + o->input_mtu + 1), o->enc_block_size);
-        if (!(o->buf = (uint8_t *)malloc(buf_size))) {
-            goto fail1;
-        }
-    }
-    
-    // init handler job
-    BPending_Init(&o->handler_job, pg, (BPending_handler)handler_job_hander, o);
-    
-    // have no work
-    o->tw_have = 0;
-    
-    DebugObject_Init(&o->d_obj);
-    
-    return 1;
-    
-fail1:
-    PacketRecvInterface_Free(&o->output);
-    if (SPPROTO_HAVE_OTP(o->sp_params)) {
-        OTPGenerator_Free(&o->otpgen);
-    }
-fail0:
-    return 0;
-}
-
-void SPProtoEncoder_Free (SPProtoEncoder *o)
-{
-    DebugObject_Free(&o->d_obj);
-    
-    // free work
-    if (o->tw_have) {
-        BThreadWork_Free(&o->tw);
-    }
-    
-    // free handler job
-    BPending_Free(&o->handler_job);
-    
-    // free plaintext buffer
-    if (SPPROTO_HAVE_ENCRYPTION(o->sp_params)) {
-        free(o->buf);
-    }
-    
-    // free output
-    PacketRecvInterface_Free(&o->output);
-    
-    // free encryptor
-    if (SPPROTO_HAVE_ENCRYPTION(o->sp_params) && o->have_encryption_key) {
-        BEncryption_Free(&o->encryptor);
-    }
-    
-    // free otp generator
-    if (SPPROTO_HAVE_OTP(o->sp_params)) {
-        OTPGenerator_Free(&o->otpgen);
-    }
-}
-
-PacketRecvInterface * SPProtoEncoder_GetOutput (SPProtoEncoder *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->output;
-}
-
-void SPProtoEncoder_SetEncryptionKey (SPProtoEncoder *o, uint8_t *encryption_key)
-{
-    ASSERT(SPPROTO_HAVE_ENCRYPTION(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    // stop existing work
-    maybe_stop_work(o);
-    
-    // free encryptor
-    if (o->have_encryption_key) {
-        BEncryption_Free(&o->encryptor);
-    }
-    
-    // init encryptor
-    BEncryption_Init(&o->encryptor, BENCRYPTION_MODE_ENCRYPT, o->sp_params.encryption_mode, encryption_key);
-    
-    // have encryption key
-    o->have_encryption_key = 1;
-    
-    // possibly continue I/O
-    maybe_encode(o);
-}
-
-void SPProtoEncoder_RemoveEncryptionKey (SPProtoEncoder *o)
-{
-    ASSERT(SPPROTO_HAVE_ENCRYPTION(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    // stop existing work
-    maybe_stop_work(o);
-    
-    if (o->have_encryption_key) {
-        // free encryptor
-        BEncryption_Free(&o->encryptor);
-        
-        // have no encryption key
-        o->have_encryption_key = 0;
-    }
-}
-
-void SPProtoEncoder_SetOTPSeed (SPProtoEncoder *o, uint16_t seed_id, uint8_t *key, uint8_t *iv)
-{
-    ASSERT(SPPROTO_HAVE_OTP(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    // give seed to OTP generator
-    OTPGenerator_SetSeed(&o->otpgen, key, iv);
-    
-    // remember seed ID
-    o->otpgen_pending_seed_id = seed_id;
-}
-
-void SPProtoEncoder_RemoveOTPSeed (SPProtoEncoder *o)
-{
-    ASSERT(SPPROTO_HAVE_OTP(o->sp_params))
-    DebugObject_Access(&o->d_obj);
-    
-    // reset OTP generator
-    OTPGenerator_Reset(&o->otpgen);
-}
-
-void SPProtoEncoder_SetHandlers (SPProtoEncoder *o, SPProtoEncoder_handler handler, void *user)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    o->handler = handler;
-    o->user = user;
-}
diff --git a/external/badvpn_dns/client/SPProtoEncoder.h b/external/badvpn_dns/client/SPProtoEncoder.h
deleted file mode 100644
index 874f391..0000000
--- a/external/badvpn_dns/client/SPProtoEncoder.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/**
- * @file SPProtoEncoder.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Object which encodes packets according to SPProto.
- */
-
-#ifndef BADVPN_CLIENT_SPPROTOENCODER_H
-#define BADVPN_CLIENT_SPPROTOENCODER_H
-
-#include <stdint.h>
-
-#include <misc/debug.h>
-#include <protocol/spproto.h>
-#include <base/DebugObject.h>
-#include <security/BEncryption.h>
-#include <security/OTPGenerator.h>
-#include <flow/PacketRecvInterface.h>
-#include <threadwork/BThreadWork.h>
-
-/**
- * Event context handler called when the remaining number of
- * OTPs equals the warning number after having encoded a packet.
- * 
- * @param user as in {@link SPProtoEncoder_Init}
- */
-typedef void (*SPProtoEncoder_handler) (void *user);
-
-/**
- * Object which encodes packets according to SPProto.
- *
- * Input is with {@link PacketRecvInterface}.
- * Output is with {@link PacketRecvInterface}.
- */
-typedef struct {
-    PacketRecvInterface *input;
-    struct spproto_security_params sp_params;
-    int otp_warning_count;
-    SPProtoEncoder_handler handler;
-    BThreadWorkDispatcher *twd;
-    void *user;
-    int hash_size;
-    int enc_block_size;
-    int enc_key_size;
-    OTPGenerator otpgen;
-    uint16_t otpgen_seed_id;
-    uint16_t otpgen_pending_seed_id;
-    int have_encryption_key;
-    BEncryption encryptor;
-    int input_mtu;
-    int output_mtu;
-    int in_len;
-    PacketRecvInterface output;
-    int out_have;
-    uint8_t *out;
-    uint8_t *buf;
-    BPending handler_job;
-    int tw_have;
-    BThreadWork tw;
-    uint16_t tw_seed_id;
-    otp_t tw_otp;
-    int tw_out_len;
-    DebugObject d_obj;
-} SPProtoEncoder;
-
-/**
- * Initializes the object.
- * The object is initialized in blocked state.
- * {@link BSecurity_GlobalInitThreadSafe} must have been done if
- * {@link BThreadWorkDispatcher_UsingThreads}(twd) = 1.
- *
- * @param o the object
- * @param input input interface. Its MTU must not be too large, i.e. this must hold:
- *              spproto_carrier_mtu_for_payload_mtu(sp_params, input MTU) >= 0
- * @param sp_params SPProto security parameters
- * @param otp_warning_count If using OTPs, after how many encoded packets to call the handler.
- *                          In this case, must be >0 and <=sp_params.otp_num.
- * @param pg pending group
- * @param twd thread work dispatcher
- * @return 1 on success, 0 on failure
- */
-int SPProtoEncoder_Init (SPProtoEncoder *o, PacketRecvInterface *input, struct spproto_security_params sp_params, int otp_warning_count, BPendingGroup *pg, BThreadWorkDispatcher *twd) WARN_UNUSED;
-
-/**
- * Frees the object.
- *
- * @param o the object
- */
-void SPProtoEncoder_Free (SPProtoEncoder *o);
-
-/**
- * Returns the output interface.
- * The MTU of the output interface will depend on the input MTU and security parameters,
- * that is spproto_carrier_mtu_for_payload_mtu(sp_params, input MTU).
- *
- * @param o the object
- * @return output interface
- */
-PacketRecvInterface * SPProtoEncoder_GetOutput (SPProtoEncoder *o);
-
-/**
- * Sets an encryption key to use.
- * Encryption must be enabled.
- *
- * @param o the object
- * @param encryption_key key to use
- */
-void SPProtoEncoder_SetEncryptionKey (SPProtoEncoder *o, uint8_t *encryption_key);
-
-/**
- * Removes an encryption key if one is configured.
- * Encryption must be enabled.
- *
- * @param o the object
- */
-void SPProtoEncoder_RemoveEncryptionKey (SPProtoEncoder *o);
-
-/**
- * Sets an OTP seed to use.
- * OTPs must be enabled.
- *
- * @param o the object
- * @param seed_id seed identifier
- * @param key OTP encryption key
- * @param iv OTP initialization vector
- */
-void SPProtoEncoder_SetOTPSeed (SPProtoEncoder *o, uint16_t seed_id, uint8_t *key, uint8_t *iv);
-
-/**
- * Removes the OTP seed if one is configured.
- * OTPs must be enabled.
- *
- * @param o the object
- */
-void SPProtoEncoder_RemoveOTPSeed (SPProtoEncoder *o);
-
-/**
- * Sets handlers.
- *
- * @param o the object
- * @param handler OTP warning handler
- * @param user value to pass to handler
- */
-void SPProtoEncoder_SetHandlers (SPProtoEncoder *o, SPProtoEncoder_handler handler, void *user);
-
-#endif
diff --git a/external/badvpn_dns/client/SimpleStreamBuffer.c b/external/badvpn_dns/client/SimpleStreamBuffer.c
deleted file mode 100644
index 74448cb..0000000
--- a/external/badvpn_dns/client/SimpleStreamBuffer.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * @file SimpleStreamBuffer.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-#include <stddef.h>
-
-#include <misc/balloc.h>
-#include <misc/minmax.h>
-
-#include "SimpleStreamBuffer.h"
-
-static void try_output (SimpleStreamBuffer *o)
-{
-    ASSERT(o->output_data_len > 0)
-    
-    // calculate number of bytes to output
-    int bytes = bmin_int(o->output_data_len, o->buf_used);
-    if (bytes == 0) {
-        return;
-    }
-    
-    // copy bytes to output
-    memcpy(o->output_data, o->buf, bytes);
-    
-    // shift buffer
-    memmove(o->buf, o->buf + bytes, o->buf_used - bytes);
-    o->buf_used -= bytes;
-    
-    // forget data
-    o->output_data_len = -1;
-    
-    // done
-    StreamRecvInterface_Done(&o->output, bytes);
-}
-
-static void output_handler_recv (SimpleStreamBuffer *o, uint8_t *data, int data_len)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->output_data_len == -1)
-    ASSERT(data)
-    ASSERT(data_len > 0)
-    
-    // remember data
-    o->output_data = data;
-    o->output_data_len = data_len;
-    
-    try_output(o);
-}
-
-int SimpleStreamBuffer_Init (SimpleStreamBuffer *o, int buf_size, BPendingGroup *pg)
-{
-    ASSERT(buf_size > 0)
-    
-    // init arguments
-    o->buf_size = buf_size;
-    
-    // init output
-    StreamRecvInterface_Init(&o->output, (StreamRecvInterface_handler_recv)output_handler_recv, o, pg);
-    
-    // allocate buffer
-    if (!(o->buf = (uint8_t *)BAlloc(buf_size))) {
-        goto fail1;
-    }
-    
-    // init buffer state
-    o->buf_used = 0;
-    
-    // set no output data
-    o->output_data_len = -1;
-    
-    DebugObject_Init(&o->d_obj);
-    return 1;
-    
-fail1:
-    StreamRecvInterface_Free(&o->output);
-    return 0;
-}
-
-void SimpleStreamBuffer_Free (SimpleStreamBuffer *o)
-{
-    DebugObject_Free(&o->d_obj);
-    
-    // free buffer
-    BFree(o->buf);
-    
-    // free output
-    StreamRecvInterface_Free(&o->output);
-}
-
-StreamRecvInterface * SimpleStreamBuffer_GetOutput (SimpleStreamBuffer *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->output;
-}
-
-int SimpleStreamBuffer_Write (SimpleStreamBuffer *o, uint8_t *data, int data_len)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(data_len >= 0)
-    
-    if (data_len > o->buf_size - o->buf_used) {
-        return 0;
-    }
-    
-    // copy to buffer
-    memcpy(o->buf + o->buf_used, data, data_len);
-    
-    // update buffer state
-    o->buf_used += data_len;
-    
-    // continue outputting
-    if (o->output_data_len > 0) {
-        try_output(o);
-    }
-    
-    return 1;
-}
diff --git a/external/badvpn_dns/client/SimpleStreamBuffer.h b/external/badvpn_dns/client/SimpleStreamBuffer.h
deleted file mode 100644
index 31a55f7..0000000
--- a/external/badvpn_dns/client/SimpleStreamBuffer.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * @file SimpleStreamBuffer.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BADVPN_SIMPLESTREAMBUFFER_H
-#define BADVPN_SIMPLESTREAMBUFFER_H
-
-#include <misc/debug.h>
-#include <base/DebugObject.h>
-#include <flow/StreamRecvInterface.h>
-
-typedef struct {
-    int buf_size;
-    StreamRecvInterface output;
-    uint8_t *buf;
-    int buf_used;
-    uint8_t *output_data;
-    int output_data_len;
-    DebugObject d_obj;
-} SimpleStreamBuffer;
-
-int SimpleStreamBuffer_Init (SimpleStreamBuffer *o, int buf_size, BPendingGroup *pg) WARN_UNUSED;
-void SimpleStreamBuffer_Free (SimpleStreamBuffer *o);
-StreamRecvInterface * SimpleStreamBuffer_GetOutput (SimpleStreamBuffer *o);
-int SimpleStreamBuffer_Write (SimpleStreamBuffer *o, uint8_t *data, int data_len) WARN_UNUSED;
-
-#endif
diff --git a/external/badvpn_dns/client/SinglePacketSource.c b/external/badvpn_dns/client/SinglePacketSource.c
deleted file mode 100644
index 1c6a573..0000000
--- a/external/badvpn_dns/client/SinglePacketSource.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * @file SinglePacketSource.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-
-#include <misc/debug.h>
-
-#include "SinglePacketSource.h"
-
-static void output_handler_recv (SinglePacketSource *o, uint8_t *data)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    // if we already sent one packet, stop
-    if (o->sent) {
-        return;
-    }
-    
-    // set sent
-    o->sent = 1;
-    
-    // write packet
-    memcpy(data, o->packet, o->packet_len);
-    
-    // done
-    PacketRecvInterface_Done(&o->output, o->packet_len);
-}
-
-void SinglePacketSource_Init (SinglePacketSource *o, uint8_t *packet, int packet_len, BPendingGroup *pg)
-{
-    ASSERT(packet_len >= 0)
-    
-    // init arguments
-    o->packet = packet;
-    o->packet_len = packet_len;
-    
-    // set not sent
-    o->sent = 0;
-    
-    // init output
-    PacketRecvInterface_Init(&o->output, o->packet_len, (PacketRecvInterface_handler_recv)output_handler_recv, o, pg);
-    
-    DebugObject_Init(&o->d_obj);
-}
-
-void SinglePacketSource_Free (SinglePacketSource *o)
-{
-    DebugObject_Free(&o->d_obj);
-    
-    // free output
-    PacketRecvInterface_Free(&o->output);
-}
-
-PacketRecvInterface * SinglePacketSource_GetOutput (SinglePacketSource *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->output;
-}
diff --git a/external/badvpn_dns/client/SinglePacketSource.h b/external/badvpn_dns/client/SinglePacketSource.h
deleted file mode 100644
index 85ca426..0000000
--- a/external/badvpn_dns/client/SinglePacketSource.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * @file SinglePacketSource.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BADVPN_SINGLEPACKETSOURCE_H
-#define BADVPN_SINGLEPACKETSOURCE_H
-
-#include <base/DebugObject.h>
-#include <flow/PacketRecvInterface.h>
-
-/**
- * An object which provides a single packet through {@link PacketRecvInterface}.
- */
-typedef struct {
-    uint8_t *packet;
-    int packet_len;
-    int sent;
-    PacketRecvInterface output;
-    DebugObject d_obj;
-} SinglePacketSource;
-
-/**
- * Initializes the object.
- * 
- * @param o the object
- * @param packet packet to provide to the output. Must stay available until the packet is provided.
- * @param packet_len length of packet. Must be >=0.
- * @param pg pending group we live in
- */
-void SinglePacketSource_Init (SinglePacketSource *o, uint8_t *packet, int packet_len, BPendingGroup *pg);
-
-/**
- * Frees the object.
- * 
- * @param o the object
- */
-void SinglePacketSource_Free (SinglePacketSource *o);
-
-/**
- * Returns the output interface.
- * The MTU of the interface will be packet_len.
- * 
- * @param o the object
- * @return output interface
- */
-PacketRecvInterface * SinglePacketSource_GetOutput (SinglePacketSource *o);
-
-#endif
diff --git a/external/badvpn_dns/client/StreamPeerIO.c b/external/badvpn_dns/client/StreamPeerIO.c
deleted file mode 100644
index 3113c3b..0000000
--- a/external/badvpn_dns/client/StreamPeerIO.c
+++ /dev/null
@@ -1,712 +0,0 @@
-/**
- * @file StreamPeerIO.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-
-#include <ssl.h>
-#include <sslerr.h>
-
-#include <misc/offset.h>
-#include <misc/byteorder.h>
-
-#include <client/StreamPeerIO.h>
-
-#include <generated/blog_channel_StreamPeerIO.h>
-
-#define MODE_NONE 0
-#define MODE_CONNECT 1
-#define MODE_LISTEN 2
-
-#define CONNECT_STATE_CONNECTING 0
-#define CONNECT_STATE_HANDSHAKE 1
-#define CONNECT_STATE_SENDING 2
-#define CONNECT_STATE_SENT 3
-#define CONNECT_STATE_FINISHED 4
-
-#define LISTEN_STATE_LISTENER 0
-#define LISTEN_STATE_GOTCLIENT 1
-#define LISTEN_STATE_FINISHED 2
-
-#define PeerLog(_o, ...) BLog_LogViaFunc((_o)->logfunc, (_o)->user, BLOG_CURRENT_CHANNEL, __VA_ARGS__)
-
-static void decoder_handler_error (StreamPeerIO *pio);
-static void connector_handler (StreamPeerIO *pio, int is_error);
-static void connection_handler (StreamPeerIO *pio, int event);
-static void connect_sslcon_handler (StreamPeerIO *pio, int event);
-static void pwsender_handler (StreamPeerIO *pio);
-static void listener_handler_client (StreamPeerIO *pio, sslsocket *sock);
-static int init_io (StreamPeerIO *pio, sslsocket *sock);
-static void free_io (StreamPeerIO *pio);
-static void sslcon_handler (StreamPeerIO *pio, int event);
-static SECStatus client_auth_certificate_callback (StreamPeerIO *pio, PRFileDesc *fd, PRBool checkSig, PRBool isServer);
-static SECStatus client_client_auth_data_callback (StreamPeerIO *pio, PRFileDesc *fd, CERTDistNames *caNames, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey);
-static int compare_certificate (StreamPeerIO *pio, CERTCertificate *cert);
-static void reset_state (StreamPeerIO *pio);
-static void reset_and_report_error (StreamPeerIO *pio);
-
-void decoder_handler_error (StreamPeerIO *pio)
-{
-    DebugObject_Access(&pio->d_obj);
-    
-    PeerLog(pio, BLOG_ERROR, "decoder error");
-    
-    reset_and_report_error(pio);
-    return;
-}
-
-void connector_handler (StreamPeerIO *pio, int is_error)
-{
-    DebugObject_Access(&pio->d_obj);
-    ASSERT(pio->mode == MODE_CONNECT)
-    ASSERT(pio->connect.state == CONNECT_STATE_CONNECTING)
-    
-    // check connection result
-    if (is_error) {
-        PeerLog(pio, BLOG_NOTICE, "connection failed");
-        goto fail0;
-    }
-    
-    // init connection
-    if (!BConnection_Init(&pio->connect.sock.con, BConnection_source_connector(&pio->connect.connector), pio->reactor, pio, (BConnection_handler)connection_handler)) {
-        PeerLog(pio, BLOG_ERROR, "BConnection_Init failed");
-        goto fail0;
-    }
-    
-    if (pio->ssl) {
-        // init connection interfaces
-        BConnection_SendAsync_Init(&pio->connect.sock.con);
-        BConnection_RecvAsync_Init(&pio->connect.sock.con);
-        
-        // create bottom NSPR file descriptor
-        if (!BSSLConnection_MakeBackend(&pio->connect.sock.bottom_prfd, BConnection_SendAsync_GetIf(&pio->connect.sock.con), BConnection_RecvAsync_GetIf(&pio->connect.sock.con), pio->twd, pio->ssl_flags)) {
-            PeerLog(pio, BLOG_ERROR, "BSSLConnection_MakeBackend failed");
-            goto fail1;
-        }
-        
-        // create SSL file descriptor from the bottom NSPR file descriptor
-        if (!(pio->connect.sock.ssl_prfd = SSL_ImportFD(NULL, &pio->connect.sock.bottom_prfd))) {
-            ASSERT_FORCE(PR_Close(&pio->connect.sock.bottom_prfd) == PR_SUCCESS)
-            goto fail1;
-        }
-        
-        // set client mode
-        if (SSL_ResetHandshake(pio->connect.sock.ssl_prfd, PR_FALSE) != SECSuccess) {
-            PeerLog(pio, BLOG_ERROR, "SSL_ResetHandshake failed");
-            goto fail2;
-        }
-        
-        // set verify peer certificate hook
-        if (SSL_AuthCertificateHook(pio->connect.sock.ssl_prfd, (SSLAuthCertificate)client_auth_certificate_callback, pio) != SECSuccess) {
-            PeerLog(pio, BLOG_ERROR, "SSL_AuthCertificateHook failed");
-            goto fail2;
-        }
-        
-        // set client certificate callback
-        if (SSL_GetClientAuthDataHook(pio->connect.sock.ssl_prfd, (SSLGetClientAuthData)client_client_auth_data_callback, pio) != SECSuccess) {
-            PeerLog(pio, BLOG_ERROR, "SSL_GetClientAuthDataHook failed");
-            goto fail2;
-        }
-        
-        // init BSSLConnection
-        BSSLConnection_Init(&pio->connect.sslcon, pio->connect.sock.ssl_prfd, 1, BReactor_PendingGroup(pio->reactor), pio, (BSSLConnection_handler)connect_sslcon_handler);
-        
-        // change state
-        pio->connect.state = CONNECT_STATE_HANDSHAKE;
-    } else {
-        // init connection send interface
-        BConnection_SendAsync_Init(&pio->connect.sock.con);
-        
-        // init password sender
-        SingleStreamSender_Init(&pio->connect.pwsender, (uint8_t *)&pio->connect.password, sizeof(pio->connect.password), BConnection_SendAsync_GetIf(&pio->connect.sock.con), BReactor_PendingGroup(pio->reactor), pio, (SingleStreamSender_handler)pwsender_handler);
-        
-        // change state
-        pio->connect.state = CONNECT_STATE_SENDING;
-    }
-    
-    return;
-
-    if (pio->ssl) {
-fail2:
-        ASSERT_FORCE(PR_Close(pio->connect.sock.ssl_prfd) == PR_SUCCESS)
-fail1:
-        BConnection_RecvAsync_Free(&pio->connect.sock.con);
-        BConnection_SendAsync_Free(&pio->connect.sock.con);
-    }
-    BConnection_Free(&pio->connect.sock.con);
-fail0:
-    reset_and_report_error(pio);
-    return;
-}
-
-void connection_handler (StreamPeerIO *pio, int event)
-{
-    DebugObject_Access(&pio->d_obj);
-    ASSERT(pio->mode == MODE_CONNECT || pio->mode == MODE_LISTEN)
-    ASSERT(!(pio->mode == MODE_CONNECT) || pio->connect.state >= CONNECT_STATE_HANDSHAKE)
-    ASSERT(!(pio->mode == MODE_LISTEN) || pio->listen.state >= LISTEN_STATE_FINISHED)
-    
-    if (event == BCONNECTION_EVENT_RECVCLOSED) {
-        PeerLog(pio, BLOG_NOTICE, "connection closed");
-    } else {
-        PeerLog(pio, BLOG_NOTICE, "connection error");
-    }
-    
-    reset_and_report_error(pio);
-    return;
-}
-
-void connect_sslcon_handler (StreamPeerIO *pio, int event)
-{
-    DebugObject_Access(&pio->d_obj);
-    ASSERT(pio->ssl)
-    ASSERT(pio->mode == MODE_CONNECT)
-    ASSERT(pio->connect.state == CONNECT_STATE_HANDSHAKE || pio->connect.state == CONNECT_STATE_SENDING)
-    ASSERT(event == BSSLCONNECTION_EVENT_UP || event == BSSLCONNECTION_EVENT_ERROR)
-    
-    if (event == BSSLCONNECTION_EVENT_ERROR) {
-        PeerLog(pio, BLOG_NOTICE, "SSL error");
-        
-        reset_and_report_error(pio);
-        return;
-    }
-    
-    // handshake complete
-    ASSERT(pio->connect.state == CONNECT_STATE_HANDSHAKE)
-    
-    // remove client certificate callback
-    if (SSL_GetClientAuthDataHook(pio->connect.sock.ssl_prfd, NULL, NULL) != SECSuccess) {
-        PeerLog(pio, BLOG_ERROR, "SSL_GetClientAuthDataHook failed");
-        goto fail0;
-    }
-    
-    // remove verify peer certificate callback
-    if (SSL_AuthCertificateHook(pio->connect.sock.ssl_prfd, NULL, NULL) != SECSuccess) {
-        PeerLog(pio, BLOG_ERROR, "SSL_AuthCertificateHook failed");
-        goto fail0;
-    }
-    
-    // init password sender
-    SingleStreamSender_Init(&pio->connect.pwsender, (uint8_t *)&pio->connect.password, sizeof(pio->connect.password), BSSLConnection_GetSendIf(&pio->connect.sslcon), BReactor_PendingGroup(pio->reactor), pio, (SingleStreamSender_handler)pwsender_handler);
-    
-    // change state
-    pio->connect.state = CONNECT_STATE_SENDING;
-    
-    return;
-    
-fail0:
-    reset_and_report_error(pio);
-    return;
-}
-
-void pwsender_handler (StreamPeerIO *pio)
-{
-    DebugObject_Access(&pio->d_obj);
-    ASSERT(pio->mode == MODE_CONNECT)
-    ASSERT(pio->connect.state == CONNECT_STATE_SENDING)
-    
-    // stop using any buffers before they get freed
-    if (pio->ssl) {
-        BSSLConnection_ReleaseBuffers(&pio->connect.sslcon);
-    }
-    
-    // free password sender
-    SingleStreamSender_Free(&pio->connect.pwsender);
-    
-    if (pio->ssl) {
-        // free BSSLConnection (we used the send interface)
-        BSSLConnection_Free(&pio->connect.sslcon);
-    } else {
-        // init connection send interface
-        BConnection_SendAsync_Free(&pio->connect.sock.con);
-    }
-    
-    // change state
-    pio->connect.state = CONNECT_STATE_SENT;
-    
-    // setup i/o
-    if (!init_io(pio, &pio->connect.sock)) {
-        goto fail0;
-    }
-    
-    // change state
-    pio->connect.state = CONNECT_STATE_FINISHED;
-    
-    return;
-    
-fail0:
-    reset_and_report_error(pio);
-    return;
-}
-
-void listener_handler_client (StreamPeerIO *pio, sslsocket *sock)
-{
-    DebugObject_Access(&pio->d_obj);
-    ASSERT(pio->mode == MODE_LISTEN)
-    ASSERT(pio->listen.state == LISTEN_STATE_LISTENER)
-    
-    // remember socket
-    pio->listen.sock = sock;
-    
-    // set connection handler
-    BConnection_SetHandlers(&pio->listen.sock->con, pio, (BConnection_handler)connection_handler);
-    
-    // change state
-    pio->listen.state = LISTEN_STATE_GOTCLIENT;
-    
-    // check ceritficate
-    if (pio->ssl) {
-        CERTCertificate *peer_cert = SSL_PeerCertificate(pio->listen.sock->ssl_prfd);
-        if (!peer_cert) {
-            PeerLog(pio, BLOG_ERROR, "SSL_PeerCertificate failed");
-            goto fail0;
-        }
-        
-        // compare certificate to the one provided by the server
-        if (!compare_certificate(pio, peer_cert)) {
-            CERT_DestroyCertificate(peer_cert);
-            goto fail0;
-        }
-        
-        CERT_DestroyCertificate(peer_cert);
-    }
-    
-    // setup i/o
-    if (!init_io(pio, pio->listen.sock)) {
-        goto fail0;
-    }
-    
-    // change state
-    pio->listen.state = LISTEN_STATE_FINISHED;
-    
-    return;
-    
-fail0:
-    reset_and_report_error(pio);
-    return;
-}
-
-int init_io (StreamPeerIO *pio, sslsocket *sock)
-{
-    ASSERT(!pio->sock)
-    
-    // limit socket send buffer, else our scheduling is pointless
-    if (pio->sock_sndbuf > 0) {
-        if (!BConnection_SetSendBuffer(&sock->con, pio->sock_sndbuf)) {
-            PeerLog(pio, BLOG_WARNING, "BConnection_SetSendBuffer failed");
-        }
-    }
-    
-    if (pio->ssl) {
-        // init BSSLConnection
-        BSSLConnection_Init(&pio->sslcon, sock->ssl_prfd, 0, BReactor_PendingGroup(pio->reactor), pio, (BSSLConnection_handler)sslcon_handler);
-    } else {
-        // init connection interfaces
-        BConnection_SendAsync_Init(&sock->con);
-        BConnection_RecvAsync_Init(&sock->con);
-    }
-    
-    StreamPassInterface *send_if = (pio->ssl ? BSSLConnection_GetSendIf(&pio->sslcon) : BConnection_SendAsync_GetIf(&sock->con));
-    StreamRecvInterface *recv_if = (pio->ssl ? BSSLConnection_GetRecvIf(&pio->sslcon) : BConnection_RecvAsync_GetIf(&sock->con));
-    
-    // init receiving
-    StreamRecvConnector_ConnectInput(&pio->input_connector, recv_if);
-    
-    // init sending
-    PacketStreamSender_Init(&pio->output_pss, send_if, PACKETPROTO_ENCLEN(pio->payload_mtu), BReactor_PendingGroup(pio->reactor));
-    PacketPassConnector_ConnectOutput(&pio->output_connector, PacketStreamSender_GetInput(&pio->output_pss));
-    
-    pio->sock = sock;
-    
-    return 1;
-}
-
-void free_io (StreamPeerIO *pio)
-{
-    ASSERT(pio->sock)
-    
-    // stop using any buffers before they get freed
-    if (pio->ssl) {
-        BSSLConnection_ReleaseBuffers(&pio->sslcon);
-    }
-    
-    // reset decoder
-    PacketProtoDecoder_Reset(&pio->input_decoder);
-    
-    // free sending
-    PacketPassConnector_DisconnectOutput(&pio->output_connector);
-    PacketStreamSender_Free(&pio->output_pss);
-    
-    // free receiving
-    StreamRecvConnector_DisconnectInput(&pio->input_connector);
-    
-    if (pio->ssl) {
-        // free BSSLConnection
-        BSSLConnection_Free(&pio->sslcon);
-    } else {
-        // free connection interfaces
-        BConnection_RecvAsync_Free(&pio->sock->con);
-        BConnection_SendAsync_Free(&pio->sock->con);
-    }
-    
-    pio->sock = NULL;
-}
-
-void sslcon_handler (StreamPeerIO *pio, int event)
-{
-    DebugObject_Access(&pio->d_obj);
-    ASSERT(pio->ssl)
-    ASSERT(pio->mode == MODE_CONNECT || pio->mode == MODE_LISTEN)
-    ASSERT(!(pio->mode == MODE_CONNECT) || pio->connect.state == CONNECT_STATE_FINISHED)
-    ASSERT(!(pio->mode == MODE_LISTEN) || pio->listen.state == LISTEN_STATE_FINISHED)
-    ASSERT(event == BSSLCONNECTION_EVENT_ERROR)
-    
-    PeerLog(pio, BLOG_NOTICE, "SSL error");
-    
-    reset_and_report_error(pio);
-    return;
-}
-
-SECStatus client_auth_certificate_callback (StreamPeerIO *pio, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
-{
-    ASSERT(pio->ssl)
-    ASSERT(pio->mode == MODE_CONNECT)
-    ASSERT(pio->connect.state == CONNECT_STATE_HANDSHAKE)
-    DebugObject_Access(&pio->d_obj);
-    
-    // This callback is used to bypass checking the server's domain name, as peers
-    // don't have domain names. We byte-compare the certificate to the one reported
-    // by the server anyway.
-    
-    SECStatus ret = SECFailure;
-    
-    CERTCertificate *server_cert = SSL_PeerCertificate(pio->connect.sock.ssl_prfd);
-    if (!server_cert) {
-        PeerLog(pio, BLOG_ERROR, "SSL_PeerCertificate failed");
-        PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
-        goto fail1;
-    }
-    
-    if (CERT_VerifyCertNow(CERT_GetDefaultCertDB(), server_cert, PR_TRUE, certUsageSSLServer, SSL_RevealPinArg(pio->connect.sock.ssl_prfd)) != SECSuccess) {
-        goto fail2;
-    }
-    
-    // compare to certificate provided by the server
-    if (!compare_certificate(pio, server_cert)) {
-        PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
-        goto fail2;
-    }
-    
-    ret = SECSuccess;
-    
-fail2:
-    CERT_DestroyCertificate(server_cert);
-fail1:
-    return ret;
-}
-
-SECStatus client_client_auth_data_callback (StreamPeerIO *pio, PRFileDesc *fd, CERTDistNames *caNames, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey)
-{
-    ASSERT(pio->ssl)
-    ASSERT(pio->mode == MODE_CONNECT)
-    ASSERT(pio->connect.state == CONNECT_STATE_HANDSHAKE)
-    DebugObject_Access(&pio->d_obj);
-    
-    CERTCertificate *cert = CERT_DupCertificate(pio->connect.ssl_cert);
-    if (!cert) {
-        PeerLog(pio, BLOG_ERROR, "CERT_DupCertificate failed");
-        goto fail0;
-    }
-    
-    SECKEYPrivateKey *key = SECKEY_CopyPrivateKey(pio->connect.ssl_key);
-    if (!key) {
-        PeerLog(pio, BLOG_ERROR, "SECKEY_CopyPrivateKey failed");
-        goto fail1;
-    }
-    
-    *pRetCert = cert;
-    *pRetKey = key;
-    return SECSuccess;
-    
-fail1:
-    CERT_DestroyCertificate(cert);
-fail0:
-    return SECFailure;
-}
-
-int compare_certificate (StreamPeerIO *pio, CERTCertificate *cert)
-{
-    ASSERT(pio->ssl)
-    
-    SECItem der = cert->derCert;
-    if (der.len != pio->ssl_peer_cert_len || memcmp(der.data, pio->ssl_peer_cert, der.len)) {
-        PeerLog(pio, BLOG_NOTICE, "Client certificate doesn't match");
-        return 0;
-    }
-    
-    return 1;
-}
-
-void reset_state (StreamPeerIO *pio)
-{
-    // free resources
-    switch (pio->mode) {
-        case MODE_NONE:
-            break;
-        case MODE_LISTEN:
-            switch (pio->listen.state) {
-                case LISTEN_STATE_FINISHED:
-                    free_io(pio);
-                case LISTEN_STATE_GOTCLIENT:
-                    if (pio->ssl) {
-                        ASSERT_FORCE(PR_Close(pio->listen.sock->ssl_prfd) == PR_SUCCESS)
-                        BConnection_RecvAsync_Free(&pio->listen.sock->con);
-                        BConnection_SendAsync_Free(&pio->listen.sock->con);
-                    }
-                    BConnection_Free(&pio->listen.sock->con);
-                    free(pio->listen.sock);
-                case LISTEN_STATE_LISTENER:
-                    if (pio->listen.state == LISTEN_STATE_LISTENER) {
-                        PasswordListener_RemoveEntry(pio->listen.listener, &pio->listen.pwentry);
-                    }
-                    break;
-                default:
-                    ASSERT(0);
-            }
-            break;
-        case MODE_CONNECT:
-            switch (pio->connect.state) {
-                case CONNECT_STATE_FINISHED:
-                    free_io(pio);
-                case CONNECT_STATE_SENT:
-                case CONNECT_STATE_SENDING:
-                    if (pio->connect.state == CONNECT_STATE_SENDING) {
-                        if (pio->ssl) {
-                            BSSLConnection_ReleaseBuffers(&pio->connect.sslcon);
-                        }
-                        SingleStreamSender_Free(&pio->connect.pwsender);
-                        if (!pio->ssl) {
-                            BConnection_SendAsync_Free(&pio->connect.sock.con);
-                        }
-                    }
-                case CONNECT_STATE_HANDSHAKE:
-                    if (pio->ssl) {
-                        if (pio->connect.state == CONNECT_STATE_HANDSHAKE || pio->connect.state == CONNECT_STATE_SENDING) {
-                            BSSLConnection_Free(&pio->connect.sslcon);
-                        }
-                        ASSERT_FORCE(PR_Close(pio->connect.sock.ssl_prfd) == PR_SUCCESS)
-                        BConnection_RecvAsync_Free(&pio->connect.sock.con);
-                        BConnection_SendAsync_Free(&pio->connect.sock.con);
-                    }
-                    BConnection_Free(&pio->connect.sock.con);
-                case CONNECT_STATE_CONNECTING:
-                    BConnector_Free(&pio->connect.connector);
-                    break;
-                default:
-                    ASSERT(0);
-            }
-            break;
-        default:
-            ASSERT(0);
-    }
-    
-    // set mode none
-    pio->mode = MODE_NONE;
-    
-    ASSERT(!pio->sock)
-}
-
-void reset_and_report_error (StreamPeerIO *pio)
-{
-    reset_state(pio);
-    
-    pio->handler_error(pio->user);
-    return;
-}
-
-int StreamPeerIO_Init (
-    StreamPeerIO *pio,
-    BReactor *reactor,
-    BThreadWorkDispatcher *twd,
-    int ssl,
-    int ssl_flags,
-    uint8_t *ssl_peer_cert,
-    int ssl_peer_cert_len,
-    int payload_mtu,
-    int sock_sndbuf,
-    PacketPassInterface *user_recv_if,
-    BLog_logfunc logfunc,
-    StreamPeerIO_handler_error handler_error,
-    void *user
-)
-{
-    ASSERT(ssl == 0 || ssl == 1)
-    ASSERT(payload_mtu >= 0)
-    ASSERT(PacketPassInterface_GetMTU(user_recv_if) >= payload_mtu)
-    ASSERT(handler_error)
-    
-    // init arguments
-    pio->reactor = reactor;
-    pio->twd = twd;
-    pio->ssl = ssl;
-    if (pio->ssl) {
-        pio->ssl_flags = ssl_flags;
-        pio->ssl_peer_cert = ssl_peer_cert;
-        pio->ssl_peer_cert_len = ssl_peer_cert_len;
-    }
-    pio->payload_mtu = payload_mtu;
-    pio->sock_sndbuf = sock_sndbuf;
-    pio->logfunc = logfunc;
-    pio->handler_error = handler_error;
-    pio->user = user;
-    
-    // check payload MTU
-    if (pio->payload_mtu > PACKETPROTO_MAXPAYLOAD) {
-        PeerLog(pio, BLOG_ERROR, "payload MTU is too large");
-        goto fail0;
-    }
-    
-    // init receiveing objects
-    StreamRecvConnector_Init(&pio->input_connector, BReactor_PendingGroup(pio->reactor));
-    if (!PacketProtoDecoder_Init(&pio->input_decoder, StreamRecvConnector_GetOutput(&pio->input_connector), user_recv_if, BReactor_PendingGroup(pio->reactor), pio,
-        (PacketProtoDecoder_handler_error)decoder_handler_error
-    )) {
-        PeerLog(pio, BLOG_ERROR, "FlowErrorDomain_Init failed");
-        goto fail1;
-    }
-    
-    // init sending objects
-    PacketCopier_Init(&pio->output_user_copier, pio->payload_mtu, BReactor_PendingGroup(pio->reactor));
-    PacketProtoEncoder_Init(&pio->output_user_ppe, PacketCopier_GetOutput(&pio->output_user_copier), BReactor_PendingGroup(pio->reactor));
-    PacketPassConnector_Init(&pio->output_connector, PACKETPROTO_ENCLEN(pio->payload_mtu), BReactor_PendingGroup(pio->reactor));
-    if (!SinglePacketBuffer_Init(&pio->output_user_spb, PacketProtoEncoder_GetOutput(&pio->output_user_ppe), PacketPassConnector_GetInput(&pio->output_connector), BReactor_PendingGroup(pio->reactor))) {
-        PeerLog(pio, BLOG_ERROR, "SinglePacketBuffer_Init failed");
-        goto fail2;
-    }
-    
-    // set mode none
-    pio->mode = MODE_NONE;
-    
-    // set no socket
-    pio->sock = NULL;
-    
-    DebugObject_Init(&pio->d_obj);
-    return 1;
-    
-fail2:
-    PacketPassConnector_Free(&pio->output_connector);
-    PacketProtoEncoder_Free(&pio->output_user_ppe);
-    PacketCopier_Free(&pio->output_user_copier);
-    PacketProtoDecoder_Free(&pio->input_decoder);
-fail1:
-    StreamRecvConnector_Free(&pio->input_connector);
-fail0:
-    return 0;
-}
-
-void StreamPeerIO_Free (StreamPeerIO *pio)
-{
-    DebugObject_Free(&pio->d_obj);
-
-    // reset state
-    reset_state(pio);
-    
-    // free sending objects
-    SinglePacketBuffer_Free(&pio->output_user_spb);
-    PacketPassConnector_Free(&pio->output_connector);
-    PacketProtoEncoder_Free(&pio->output_user_ppe);
-    PacketCopier_Free(&pio->output_user_copier);
-    
-    // free receiveing objects
-    PacketProtoDecoder_Free(&pio->input_decoder);
-    StreamRecvConnector_Free(&pio->input_connector);
-}
-
-PacketPassInterface * StreamPeerIO_GetSendInput (StreamPeerIO *pio)
-{
-    DebugObject_Access(&pio->d_obj);
-    
-    return PacketCopier_GetInput(&pio->output_user_copier);
-}
-
-int StreamPeerIO_Connect (StreamPeerIO *pio, BAddr addr, uint64_t password, CERTCertificate *ssl_cert, SECKEYPrivateKey *ssl_key)
-{
-    DebugObject_Access(&pio->d_obj);
-    
-    // reset state
-    reset_state(pio);
-    
-    // check address
-    if (!BConnection_AddressSupported(addr)) {
-        PeerLog(pio, BLOG_ERROR, "BConnection_AddressSupported failed");
-        goto fail0;
-    }
-    
-    // init connector
-    if (!BConnector_Init(&pio->connect.connector, addr, pio->reactor, pio, (BConnector_handler)connector_handler)) {
-        PeerLog(pio, BLOG_ERROR, "BConnector_Init failed");
-        goto fail0;
-    }
-    
-    // remember data
-    if (pio->ssl) {
-        pio->connect.ssl_cert = ssl_cert;
-        pio->connect.ssl_key = ssl_key;
-    }
-    pio->connect.password = htol64(password);
-    
-    // set state
-    pio->mode = MODE_CONNECT;
-    pio->connect.state = CONNECT_STATE_CONNECTING;
-    
-    return 1;
-    
-fail0:
-    return 0;
-}
-
-void StreamPeerIO_Listen (StreamPeerIO *pio, PasswordListener *listener, uint64_t *password)
-{
-    DebugObject_Access(&pio->d_obj);
-    ASSERT(listener->ssl == pio->ssl)
-    
-    // reset state
-    reset_state(pio);
-    
-    // add PasswordListener entry
-    uint64_t newpass = PasswordListener_AddEntry(listener, &pio->listen.pwentry, (PasswordListener_handler_client)listener_handler_client, pio);
-    
-    // remember data
-    pio->listen.listener = listener;
-    
-    // set state
-    pio->mode = MODE_LISTEN;
-    pio->listen.state = LISTEN_STATE_LISTENER;
-    
-    *password = newpass;
-}
diff --git a/external/badvpn_dns/client/StreamPeerIO.h b/external/badvpn_dns/client/StreamPeerIO.h
deleted file mode 100644
index 0b6b260..0000000
--- a/external/badvpn_dns/client/StreamPeerIO.h
+++ /dev/null
@@ -1,222 +0,0 @@
-/**
- * @file StreamPeerIO.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Object used for communicating with a peer over TCP.
- */
-
-#ifndef BADVPN_CLIENT_STREAMPEERIO_H
-#define BADVPN_CLIENT_STREAMPEERIO_H
-
-#include <stdint.h>
-
-#include <cert.h>
-#include <keyhi.h>
-
-#include <misc/debug.h>
-#include <base/DebugObject.h>
-#include <base/BLog.h>
-#include <system/BReactor.h>
-#include <system/BConnection.h>
-#include <structure/LinkedList1.h>
-#include <flow/PacketProtoDecoder.h>
-#include <flow/PacketStreamSender.h>
-#include <flow/SinglePacketBuffer.h>
-#include <flow/PacketProtoEncoder.h>
-#include <flow/PacketCopier.h>
-#include <flow/PacketPassConnector.h>
-#include <flow/StreamRecvConnector.h>
-#include <flow/SingleStreamSender.h>
-#include <client/PasswordListener.h>
-
-/**
- * Callback function invoked when an error occurs with the peer connection.
- * The object has entered default state.
- * May be called from within a sending Send call.
- *
- * @param user value given to {@link StreamPeerIO_Init}.
- */
-typedef void (*StreamPeerIO_handler_error) (void *user);
-
-/**
- * Object used for communicating with a peer over TCP.
- * The object has a logical state which can be one of the following:
- *     - default state
- *     - listening state
- *     - connecting state
- */
-typedef struct {
-    // common arguments
-    BReactor *reactor;
-    BThreadWorkDispatcher *twd;
-    int ssl;
-    int ssl_flags;
-    uint8_t *ssl_peer_cert;
-    int ssl_peer_cert_len;
-    int payload_mtu;
-    int sock_sndbuf;
-    BLog_logfunc logfunc;
-    StreamPeerIO_handler_error handler_error;
-    void *user;
-    
-    // persistent I/O modules
-    
-    // base sending objects
-    PacketCopier output_user_copier;
-    PacketProtoEncoder output_user_ppe;
-    SinglePacketBuffer output_user_spb;
-    PacketPassConnector output_connector;
-    
-    // receiving objects
-    StreamRecvConnector input_connector;
-    PacketProtoDecoder input_decoder;
-    
-    // connection side
-    int mode;
-    
-    union {
-        // listening data
-        struct {
-            int state;
-            PasswordListener *listener;
-            PasswordListener_pwentry pwentry;
-            sslsocket *sock;
-        } listen;
-        // connecting data
-        struct {
-            int state;
-            CERTCertificate *ssl_cert;
-            SECKEYPrivateKey *ssl_key;
-            BConnector connector;
-            sslsocket sock;
-            BSSLConnection sslcon;
-            uint64_t password;
-            SingleStreamSender pwsender;
-        } connect;
-    };
-    
-    // socket data
-    sslsocket *sock;
-    BSSLConnection sslcon;
-    
-    // sending objects
-    PacketStreamSender output_pss;
-    
-    DebugObject d_obj;
-} StreamPeerIO;
-
-/**
- * Initializes the object.
- * The object is initialized in default state.
- * {@link BLog_Init} must have been done.
- * {@link BNetwork_GlobalInit} must have been done.
- * {@link BSSLConnection_GlobalInit} must have been done if using SSL.
- *
- * @param pio the object
- * @param reactor reactor we live in
- * @param twd thread work dispatcher. May be NULL if ssl_flags does not request performing SSL
- *            operations in threads.
- * @param ssl if nonzero, SSL will be used for peer connection
- * @param ssl_flags flags passed down to {@link BSSLConnection_MakeBackend}. May be used to
- *                  request performing SSL operations in threads.
- * @param ssl_peer_cert if using SSL, the certificate we expect the peer to have
- * @param ssl_peer_cert_len if using SSL, the length of the certificate
- * @param payload_mtu maximum packet size as seen from the user. Must be >=0.
- * @param sock_sndbuf socket SO_SNDBUF option. Specify <=0 to not set it.
- * @param user_recv_if interface to use for submitting received packets. Its MTU
- *                     must be >=payload_mtu.
- * @param logfunc function which prepends the log prefix using {@link BLog_Append}
- * @param handler_error handler function invoked when a connection error occurs
- * @param user value to pass to handler functions
- * @return 1 on success, 0 on failure
- */
-int StreamPeerIO_Init (
-    StreamPeerIO *pio,
-    BReactor *reactor,
-    BThreadWorkDispatcher *twd,
-    int ssl,
-    int ssl_flags,
-    uint8_t *ssl_peer_cert,
-    int ssl_peer_cert_len,
-    int payload_mtu,
-    int sock_sndbuf,
-    PacketPassInterface *user_recv_if,
-    BLog_logfunc logfunc,
-    StreamPeerIO_handler_error handler_error,
-    void *user
-) WARN_UNUSED;
-
-/**
- * Frees the object.
- *
- * @param pio the object
- */
-void StreamPeerIO_Free (StreamPeerIO *pio);
-
-/**
- * Returns the interface for sending packets to the peer.
- * The OTP warning handler may be called from within Send calls
- * to the interface.
- *
- * @param pio the object
- * @return interface for sending packets to the peer
- */
-PacketPassInterface * StreamPeerIO_GetSendInput (StreamPeerIO *pio);
-
-/**
- * Starts an attempt to connect to the peer.
- * On success, the object enters connecting state.
- * On failure, the object enters default state.
- *
- * @param pio the object
- * @param addr address to connect to
- * @param password identification code to send to the peer
- * @param ssl_cert if using SSL, the client certificate to use. This object does not
- *                 take ownership of the certificate; it must remain valid until
- *                 the object is reset.
- * @param ssl_key if using SSL, the private key to use. This object does not take
- *                ownership of the key; it must remain valid until the object is reset.
- * @return 1 on success, 0 on failure
- */
-int StreamPeerIO_Connect (StreamPeerIO *pio, BAddr addr, uint64_t password, CERTCertificate *ssl_cert, SECKEYPrivateKey *ssl_key) WARN_UNUSED;
-
-/**
- * Starts an attempt to accept a connection from the peer.
- * The object enters listening state.
- *
- * @param pio the object
- * @param listener {@link PasswordListener} object to use for accepting a connection.
- *                 The listener must have SSL enabled if and only if this object has
- *                 SSL enabled. The listener must be available until the object is
- *                 reset or {@link StreamPeerIO_handler_up} is called.
- * @param password will return the identification code the peer should send when connecting
- */
-void StreamPeerIO_Listen (StreamPeerIO *pio, PasswordListener *listener, uint64_t *password);
-
-#endif
diff --git a/external/badvpn_dns/client/badvpn-client.8 b/external/badvpn_dns/client/badvpn-client.8
deleted file mode 100644
index 4f41203..0000000
--- a/external/badvpn_dns/client/badvpn-client.8
+++ /dev/null
@@ -1,316 +0,0 @@
-.TH badvpn-client 8 "14 July 2011"
-.SH NAME
-badvpn-client \- VPN node daemon for the BadVPN peer-to-peer VPN system
-.SH SYNOPSIS
-.B badvpn-client
-.RS
-.RB "[" --help "]"
-.br
-.RB "[" --version "]"
-.br
-.RB "[" --logger " <stdout/syslog>]"
-.br
-(logger=syslog?
-.br
-.RS
-.br
-.RB "[" --syslog-facility " <string>]"
-.br
-.RB "[" --syslog-ident " <string>]"
-.br
-.RE
-)
-.br
-.RB "[" --loglevel " <0-5/none/error/warning/notice/info/debug>]"
-.br
-.RB "[" --channel-loglevel " <channel-name> <0-5/none/error/warning/notice/info/debug>] ..."
-.br
-.RB "[" --threads " <integer>]"
-.br
-.RB "[" --ssl " " --nssdb " <string> " --client-cert-name " <string>]"
-.br
-.RB "[" --server-name " <string>]"
-.br
-.BR --server-addr " <addr>"
-.br
-.RB "[" --tapdev " <name>]"
-.br
-.RB "[" --scope " <scope_name>] ..."
-.br
-[
-.br
-.RS
-.BR --bind-addr " <addr>"
-.br
-.RB "(transport-mode=udp? " --num-ports " <num>)"
-.br
-.RB "[" --ext-addr " <addr / {server_reported}:port> <scope_name>] ..."
-.br
-.RE
-] ...
-.br
-.BR --transport-mode " <udp/tcp>"
-.br
-(transport-mode=udp?
-.br
-.RS
-.BR --encryption-mode " <blowfish/aes/none>"
-.br
-.BR --hash-mode " <md5/sha1/none>"
-.br
-.RB "[" --otp " <blowfish/aes> <num> <num-warn>]"
-.br
-.RB "[" --fragmentation-latency " <milliseconds>]"
-.br
-.RE
-)
-.br
-(transport-mode=tcp?
-.br
-.RS
-.RB "(ssl? [" --peer-ssl "])"
-.br
-.RB "[" --peer-tcp-socket-sndbuf " <bytes / 0>]"
-.br
-.RE
-)
-.br
-.RB "[" --send-buffer-size " <num-packets>]"
-.br
-.RB "[" --send-buffer-relay-size " <num-packets>]"
-.br
-.RB "[" --max-macs " <num>]"
-.br
-.RB "[" --max-groups " <num>]"
-.br
-.RB "[" --igmp-group-membership-interval " <ms>]"
-.br
-.RB "[" --igmp-last-member-query-time " <ms>]"
-.br
-.RB "[" --allow-peer-talk-without-ssl "]"
-.br
-.RE
-.SH INTRODUCTION
-.P
-This page documents the BadVPN client, a daemon for a node in a BadVPN VPN network.
-For a general description of BadVPN, see
-.BR badvpn (7).
-.SH DESCRIPTION
-.P
-The BadVPN client is a daemon that runs on a VPN node. It opens the TAP device, connects to
-the server, then keeps running while attempting to establish data connection to peers and
-tranferring data between the TAP device and the peers. Once it initializes, the program only
-terminates if it loses connection to the server, or if a signal is received.
-.SH OPTIONS
-.P
-The BadVPN client is configured entirely from command line.
-.TP
-.BR --help
-Print version and command line syntax and exit.
-.TP
-.BR --version
-Print version and exit.
-.TP
-.BR --logger " <stdout/syslog>"
-Select where to log messages. Default is stdout. Syslog is not available on Windows.
-.TP
-.BR --syslog-facility " <string>"
-When logging to syslog, set the logging facility. The facility name must be in lower case.
-.TP
-.BR --syslog-ident " <string>"
-When logging to syslog, set the ident.
-.TP
-.BR --loglevel " <0-5/none/error/warning/notice/info/debug>"
-Set the default logging level.
-.TP
-.BR --channel-loglevel " <channel-name> <0-5/none/error/warning/notice/info/debug>"
-Set the logging level for a specific logging channel.
-.TP
-.BR --threads " <integer>"
-Hint for the number of additional threads to use for potentionally long computations (such as
-encryption and OTP generation). If zero (0) (default), additional threads will be disabled and all
-computations will be done in the event loop. If negative (<0), a guess will be made, possibly
-based on the number of CPUs. If positive (>0), the given number of threads will be used.
-.TP
-.BR --ssl
-Use TLS. Requires --nssdb and --server-cert-name.
-.TP
-.BR --nssdb " <string>"
-When using TLS, the NSS database to use. Probably something like sql:/some/folder.
-.TP
-.BR --client-cert-name " <string>"
-When using TLS, the name of the certificate to use. The certificate must be readily accessible.
-.TP
-.BR --server-name " <string>"
-Set the name of the server used for validating the server's certificate. The server name defaults
-to the the name in the server address (or a numeric address).
-.TP
-.BR --server-addr " <addr>"
-Set the address for the server to listen on. See below for address format.
-.TP
-.BR --tapdev " <name>"
-Set the TAP device to use. See below on how to configure the device. A TAP device is a virtual card
-in the operating system, but rather than receiving from and sending frames to a piece of hardware,
-a program (this one) opens it to read from and write frames into. If the VPN network is set up correctly,
-the TAP devices on the VPN nodes will act as if they were all connected into a network switch.
-.TP
-.BR --scope " <scope_name>"
-Add an address scope allowed for connecting to peers. May be specified multiple times to add multiple
-scopes. The order of the scopes is irrelevant. Note that it must actually be possible to connect
-to addresses in the given scope; when another peer binds for us to connect to, we choose the first
-external address whose scope we recognize, and do not attempt further external addresses, even if
-establishing the connection fails.
-.TP
-.BR --bind-addr " <addr>"
-Add an address to allow binding on. See below for address format. When attempting to bind in order
-for some peer to connect to us, the addresses will be tried in the order they are specified. If UDP
-data transport is being used, a --num-ports option must follow to specify how many continuous ports
-to allow binding to. For the address to be useful, one or more --ext-addr options must follow.
-Note that when two peers need to establish a data connection, it is arbitrary which one will attempt
-to bind first.
-.TP
-.BR --num-ports " <num>"
-When using UDP transport, set the number of continuous ports for a previously specified bind address.
-Must follow a previous --bind-addr option.
-.TP
-.BR --ext-addr " <addr / {server_reported}:port> <scope_name>"
-Add an external address for a previously specified bind address. Must follow a previous --bind-addr
-option. May be specified multiple times to add multiple external addresses. See below for address
-format. Additionally, the IP address part can be {server_reported} to use the IPv4 address as the
-server sees us. The external addresses are tried by the connecting peer in the order they are specified.
-Note that the connecting peer only attempts to connect to the first address whose scope it recognizes
-and does not try other addresses. This means that all addresses must work for be able to communicate.
-.TP
-.BR --transport-mode " <udp/tcp>"
-Sets the transport protocol for data connections. UDP is recommended and works best for most networks.
-TCP can be used instead if the underlying network has high packet loss which your virtual network
-cannot tolerate. Must match on all peers.
-.TP
-.BR --encryption-mode " <blowfish/aes/none>"
-When using UDP transport, sets the encryption mode. None means no encryption, other options mean
-a specific cipher. Note that encryption is only useful if clients use TLS to connect to the server.
-The encryption mode must match on all peers.
-.TP
-.BR --hash-mode " <md5/sha1/none>"
-When using UDP transport, sets the hashing mode. None means no hashes, other options mean a specific
-type of hash. Note that hashing is only useful if encryption is used as well. The hash mode must
-match on all peers.
-.TP
-.BR --otp " <blowfish/aes> <num> <num-warn>"
-When using UDP transport, enables one-time passwords. The first argument specifies a block cipher
-used to generate passwords from a seed. The second argument specifies how many passwords are
-generated from a single seed. The third argument specifies after how many passwords used up for
-sending packets an attempt is made to negotiate a new seed with the other peer. num must be >0,
-and num-warn must be >0 and <=num. The difference (num - num-warn) should be large enough to allow
-a new seed to be negotiated before the sender runs out of passwords. Negotiating a seed involves
-the sending peer sending it to the receiving peer via the server and the receiving peer confirming
-it via the server. Note that one-time passwords are only useful if clients use TLS to connect to the
-server. The OTP option must match on all peers, except for num-warn.
-.TP
-.BR --fragmentation-latency " <milliseconds>"
-When using UDP transport, sets the maximum latency to sacrifice in order to pack frames into data
-packets more efficiently. If it is >=0, a timer of that many milliseconds is used to wait for further
-frames to put into an incomplete packet since the first chunk of the packet was written. If it is
-<0, packets are sent out immediately. Defaults to 0, which is the recommended setting.
-.TP
-.BR --peer-ssl
-When using TCP transport, enables TLS for data connections. Requires using TLS for server connection.
-For this to work, the peers must trust each others' cerificates, and the cerificates must grant the
-TLS server usage context. This option must match on all peers.
-.TP
-.BR --peer-tcp-socket-sndbuf " <bytes / 0>"
-Sets the value of the SO_SNDBUF socket option for peer TCP sockets (zero to not set). Lower values
-will improve fairness when data from multiple sources (local and relaying) is being sent to a
-given peer, but may result in lower bandwidth if the network's bandwidth-delay product is too big.
-.TP
-.BR --send-buffer-size " <num-packets>"
-Sets the minimum size of the peers' send buffers for sending frames originating from this system, in
-number of packets.
-.TP
-.BR --send-buffer-relay-size " <num-packets>"
-Sets the minimum size of the peers' send buffers for relaying frames from other peers, in number of
-packets.
-.TP
-.BR --max-macs " <num>"
-Sets the maximum number of MAC addresses to remember for a peer. When the number is exceeded, the least
-recently used slot will be reused.
-.TP
-.BR --max-groups " <num>"
-Sets the maximum number of IGMP group memberships to remember for a peer. When the number is exceeded,
-the least recently used slot will be reused.
-.TP
-.BR --igmp-group-membership-interval " <ms>"
-Sets the Group Membership Interval parameter for IGMP snooping, in milliseconds.
-.TP
-.BR --igmp-last-member-query-time " <ms>"
-Sets the Last Member Query Time parameter for IGMP snooping, in milliseconds.
-.TP
-.BR --allow-peer-talk-without-ssl
-When SSL is enabled, the clients not only connect to the server using SSL, but also exchange messages through
-the server through another layer of SSL. This protects the messages from attacks on the server. Older versions
-of BadVPN (<1.999.109), however, do not support this. This option allows older and newer clients to
-interoperate by not using SSL if the other peer does not support it. It does however negate the security
-benefits of using SSL, since the (potentionally compromised) server can then order peers not to use SSL.
-.SH "EXIT CODE"
-.P
-If initialization fails, exits with code 1. Otherwise runs until termination is requested or server connection
-is broken and exits with code 1.
-.SH "ADDRESS FORMAT"
-.P
-Addresses have the form ipaddr:port, where ipaddr is either an IPv4 address (name or numeric), or an
-IPv6 address enclosed in brackets [] (name or numeric again).
-.SH "TAP DEVICE CONFIGURATION"
-.P
-To use this program, you first have to configure a TAP network device that will act as an endpoint for
-the virtual network. The configuration depends on your operating system.
-.P
-Note that the client program does not configure the TAP device in any way; it only reads and writes
-frames from/to it. You are responsible for configuring it (e.g. putting it up and setting its IP address).
-.P
-.B Linux
-.P
-You need to enable the kernel configuration option CONFIG_TUN. If you enabled it as a module, you may
-have to load it (`modprobe tun`) before you can create the device.
-.P
-Then you should create a persistent TAP device for the VPN client program to open. This can be done with
-either the
-.B tunctl
-or the
-.B openvpn
-program. The device will be associated with a user account that will have permission to use it, which should
-be the same user as the client program will run as (not root!). To create the device with tunctl, use `tunctl -u <user> -t tapN`,
-and to create it with openvpn, use `openvpn --mktun --user <user> --dev tapN`, where N is a number that identifies the
-TAP device.
-.P
-Once the TAP device is created, pass `--tapdev tapN` to the client program to make it use this device. Note that the
-device will not be preserved across a shutdown of the system; consult your OS documentaton if you want to automate
-the creation or configuration of the device.
-.P
-.B Windows
-.P
-Windows does not come with a TAP driver. The client program uses the TAP-Win32 driver, which is part of OpenVPN.
-You need to install the OpenVPN open source (!) version, and in the installer enable at least the
-`TAP Virtual Ethernet Adapter` and `Add Shortcuts to Start Menu` options.
-You can get the installer at
-.br
-<http://openvpn.net/index.php/open-source/downloads.html>.
-.P
-The OpenVPN installer automatically creates one TAP device on your system when it's run for the first time.
-To create another device, use `Programs -> OpenVPN -> Utilities -> Add a new TAP virtual ethernet adapter`.
-You may have to install OpenVPN once again to make this shortcut appear.
-.P
-Once you have a TAP device, you can configure it like a physical network card. You can recognize TAP devices
-by their `Device Name` field.
-.P
-To use the device, pass `--tapdev "<driver_name>:<interface_name>"` to the client program, where <driver_name> is the name of
-the TAP driver (tap0901 for OpenVPN 2.1 and 2.2) (case sensitive), and <interface_name> is the (human) name of the TAP
-network interface (e.g. `Local Area Connection 2`).
-.SH "EXAMPLES"
-.P
-For examples of using BadVPN, see
-.BR badvpn (7).
-.SH "SEE ALSO"
-.BR badvpn-server (8),
-.BR badvpn (7)
-.SH AUTHORS
-Ambroz Bizjak <ambrop7 at gmail.com>
diff --git a/external/badvpn_dns/client/client.c b/external/badvpn_dns/client/client.c
deleted file mode 100644
index 2729d6b..0000000
--- a/external/badvpn_dns/client/client.c
+++ /dev/null
@@ -1,2997 +0,0 @@
-/**
- * @file client.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-
-#include <protocol/msgproto.h>
-#include <protocol/addr.h>
-#include <protocol/dataproto.h>
-#include <misc/version.h>
-#include <misc/debug.h>
-#include <misc/offset.h>
-#include <misc/byteorder.h>
-#include <misc/nsskey.h>
-#include <misc/loglevel.h>
-#include <misc/loggers_string.h>
-#include <misc/string_begins_with.h>
-#include <misc/open_standard_streams.h>
-#include <structure/LinkedList1.h>
-#include <base/DebugObject.h>
-#include <base/BLog.h>
-#include <security/BSecurity.h>
-#include <security/BRandom.h>
-#include <system/BSignal.h>
-#include <system/BTime.h>
-#include <system/BNetwork.h>
-#include <nspr_support/DummyPRFileDesc.h>
-#include <nspr_support/BSSLConnection.h>
-#include <server_connection/ServerConnection.h>
-#include <tuntap/BTap.h>
-#include <threadwork/BThreadWork.h>
-
-#ifndef BADVPN_USE_WINAPI
-#include <base/BLog_syslog.h>
-#endif
-
-#include <client/client.h>
-
-#include <generated/blog_channel_client.h>
-
-#define TRANSPORT_MODE_UDP 0
-#define TRANSPORT_MODE_TCP 1
-
-#define LOGGER_STDOUT 1
-#define LOGGER_SYSLOG 2
-
-// command-line options
-struct ext_addr_option  {
-    char *addr;
-    char *scope;
-};
-struct bind_addr_option {
-    char *addr;
-    int num_ports;
-    int num_ext_addrs;
-    struct ext_addr_option ext_addrs[MAX_EXT_ADDRS];
-};
-struct {
-    int help;
-    int version;
-    int logger;
-    #ifndef BADVPN_USE_WINAPI
-    char *logger_syslog_facility;
-    char *logger_syslog_ident;
-    #endif
-    int loglevel;
-    int loglevels[BLOG_NUM_CHANNELS];
-    int threads;
-    int use_threads_for_ssl_handshake;
-    int use_threads_for_ssl_data;
-    int ssl;
-    char *nssdb;
-    char *client_cert_name;
-    char *server_name;
-    char *server_addr;
-    char *tapdev;
-    int num_scopes;
-    char *scopes[MAX_SCOPES];
-    int num_bind_addrs;
-    struct bind_addr_option bind_addrs[MAX_BIND_ADDRS];
-    int transport_mode;
-    int encryption_mode;
-    int hash_mode;
-    int otp_mode;
-    int otp_num;
-    int otp_num_warn;
-    int fragmentation_latency;
-    int peer_ssl;
-    int peer_tcp_socket_sndbuf;
-    int send_buffer_size;
-    int send_buffer_relay_size;
-    int max_macs;
-    int max_groups;
-    int igmp_group_membership_interval;
-    int igmp_last_member_query_time;
-    int allow_peer_talk_without_ssl;
-    int max_peers;
-} options;
-
-// bind addresses
-struct ext_addr {
-    int server_reported_port;
-    BAddr addr; // if server_reported_port>=0, defined only after hello received
-    char scope[64];
-};
-struct bind_addr {
-    BAddr addr;
-    int num_ports;
-    int num_ext_addrs;
-    struct ext_addr ext_addrs[MAX_EXT_ADDRS];
-};
-int num_bind_addrs;
-struct bind_addr bind_addrs[MAX_BIND_ADDRS];
-
-// TCP listeners
-PasswordListener listeners[MAX_BIND_ADDRS];
-
-// SPProto parameters (UDP only)
-struct spproto_security_params sp_params;
-
-// server address we connect to
-BAddr server_addr;
-
-// server name to use for SSL
-char server_name[256];
-
-// reactor
-BReactor ss;
-
-// thread work dispatcher
-BThreadWorkDispatcher twd;
-
-// client certificate if using SSL
-CERTCertificate *client_cert;
-
-// client private key if using SSL
-SECKEYPrivateKey *client_key;
-
-// device
-BTap device;
-int device_mtu;
-
-// DataProtoSource for device input (reading)
-DataProtoSource device_dpsource;
-
-// DPReceiveDevice for device output (writing)
-DPReceiveDevice device_output_dprd;
-
-// data communication MTU
-int data_mtu;
-
-// peers list
-LinkedList1 peers;
-int num_peers;
-
-// frame decider
-FrameDecider frame_decider;
-
-// peers that can be user as relays
-LinkedList1 relays;
-
-// peers than need a relay
-LinkedList1 waiting_relay_peers;
-
-// server connection
-ServerConnection server;
-
-// my ID, defined only after server_ready
-peerid_t my_id;
-
-// fair queue for sending peer messages to the server
-PacketPassFairQueue server_queue;
-
-// whether server is ready
-int server_ready;
-
-// dying server flow
-struct server_flow *dying_server_flow;
-
-// stops event processing, causing the program to exit
-static void terminate (void);
-
-// prints program name and version to standard output
-static void print_help (const char *name);
-
-// prints program name and version to standard output
-static void print_version (void);
-
-// parses the command line
-static int parse_arguments (int argc, char *argv[]);
-
-// processes certain command line options
-static int process_arguments (void);
-
-static int ssl_flags (void);
-
-// handler for program termination request
-static void signal_handler (void *unused);
-
-// adds a new peer
-static void peer_add (peerid_t id, int flags, const uint8_t *cert, int cert_len);
-
-// removes a peer
-static void peer_remove (struct peer_data *peer, int exiting);
-
-// appends the peer log prefix to the logger
-static void peer_logfunc (struct peer_data *peer);
-
-// passes a message to the logger, prepending it info about the peer
-static void peer_log (struct peer_data *peer, int level, const char *fmt, ...);
-
-// see if we are the master relative to this peer
-static int peer_am_master (struct peer_data *peer);
-
-// frees PeerChat, disconnecting it from the server flow
-static void peer_free_chat (struct peer_data *peer);
-
-// initializes the link
-static int peer_init_link (struct peer_data *peer);
-
-// frees link resources
-static void peer_free_link (struct peer_data *peer);
-
-// frees link, relaying, waiting relaying
-static void peer_cleanup_connections (struct peer_data *peer);
-
-// registers the peer as a relay provider
-static void peer_enable_relay_provider (struct peer_data *peer);
-
-// unregisters the peer as a relay provider
-static void peer_disable_relay_provider (struct peer_data *peer);
-
-// install relaying for a peer
-static void peer_install_relaying (struct peer_data *peer, struct peer_data *relay);
-
-// uninstall relaying for a peer
-static void peer_free_relaying (struct peer_data *peer);
-
-// handle a peer that needs a relay
-static void peer_need_relay (struct peer_data *peer);
-
-// inserts the peer into the need relay list
-static void peer_register_need_relay (struct peer_data *peer);
-
-// removes the peer from the need relay list
-static void peer_unregister_need_relay (struct peer_data *peer);
-
-// handle a link setup failure
-static void peer_reset (struct peer_data *peer);
-
-// fees chat and sends resetpeer
-static void peer_resetpeer (struct peer_data *peer);
-
-// chat handlers
-static void peer_chat_handler_error (struct peer_data *peer);
-static void peer_chat_handler_message (struct peer_data *peer, uint8_t *data, int data_len);
-
-// handlers for different message types
-static void peer_msg_youconnect (struct peer_data *peer, uint8_t *data, int data_len);
-static void peer_msg_cannotconnect (struct peer_data *peer, uint8_t *data, int data_len);
-static void peer_msg_cannotbind (struct peer_data *peer, uint8_t *data, int data_len);
-static void peer_msg_seed (struct peer_data *peer, uint8_t *data, int data_len);
-static void peer_msg_confirmseed (struct peer_data *peer, uint8_t *data, int data_len);
-static void peer_msg_youretry (struct peer_data *peer, uint8_t *data, int data_len);
-
-// handler from DatagramPeerIO when we should generate a new OTP send seed
-static void peer_udp_pio_handler_seed_warning (struct peer_data *peer);
-
-// handler from DatagramPeerIO when a new OTP seed can be recognized once it was provided to it
-static void peer_udp_pio_handler_seed_ready (struct peer_data *peer);
-
-// handler from DatagramPeerIO when an error occurs on the connection
-static void peer_udp_pio_handler_error (struct peer_data *peer);
-
-// handler from StreamPeerIO when an error occurs on the connection
-static void peer_tcp_pio_handler_error (struct peer_data *peer);
-
-// peer retry timer handler. The timer is used only on the master side,
-// wither when we detect an error, or the peer reports an error.
-static void peer_reset_timer_handler (struct peer_data *peer);
-
-// start binding, according to the protocol
-static void peer_start_binding (struct peer_data *peer);
-
-// tries binding on one address, according to the protocol
-static void peer_bind (struct peer_data *peer);
-
-static void peer_bind_one_address (struct peer_data *peer, int addr_index, int *cont);
-
-static void peer_connect (struct peer_data *peer, BAddr addr, uint8_t *encryption_key, uint64_t password);
-
-static int peer_start_msg (struct peer_data *peer, void **data, int type, int len);
-
-static void peer_end_msg (struct peer_data *peer);
-
-// sends a message with no payload to the peer
-static void peer_send_simple (struct peer_data *peer, int msgid);
-
-static void peer_send_conectinfo (struct peer_data *peer, int addr_index, int port_adjust, uint8_t *enckey, uint64_t pass);
-
-static void peer_send_confirmseed (struct peer_data *peer, uint16_t seed_id);
-
-// handler for peer DataProto up state changes
-static void peer_dataproto_handler (struct peer_data *peer, int up);
-
-// looks for a peer with the given ID
-static struct peer_data * find_peer_by_id (peerid_t id);
-
-// device error handler
-static void device_error_handler (void *unused);
-
-// DataProtoSource handler for packets from the device
-static void device_dpsource_handler (void *unused, const uint8_t *frame, int frame_len);
-
-// assign relays to clients waiting for them
-static void assign_relays (void);
-
-// checks if the given address scope is known (i.e. we can connect to an address in it)
-static char * address_scope_known (uint8_t *name, int name_len);
-
-// handlers for server messages
-static void server_handler_error (void *user);
-static void server_handler_ready (void *user, peerid_t param_my_id, uint32_t ext_ip);
-static void server_handler_newclient (void *user, peerid_t peer_id, int flags, const uint8_t *cert, int cert_len);
-static void server_handler_endclient (void *user, peerid_t peer_id);
-static void server_handler_message (void *user, peerid_t peer_id, uint8_t *data, int data_len);
-
-// jobs
-static void peer_job_send_seed (struct peer_data *peer);
-static void peer_job_init (struct peer_data *peer);
-
-// server flows
-static struct server_flow * server_flow_init (void);
-static void server_flow_free (struct server_flow *flow);
-static void server_flow_die (struct server_flow *flow);
-static void server_flow_qflow_handler_busy (struct server_flow *flow);
-static void server_flow_connect (struct server_flow *flow, PacketRecvInterface *input);
-static void server_flow_disconnect (struct server_flow *flow);
-
-int main (int argc, char *argv[])
-{
-    if (argc <= 0) {
-        return 1;
-    }
-    
-    // open standard streams
-    open_standard_streams();
-    
-    // parse command-line arguments
-    if (!parse_arguments(argc, argv)) {
-        fprintf(stderr, "Failed to parse arguments\n");
-        print_help(argv[0]);
-        goto fail0;
-    }
-    
-    // handle --help and --version
-    if (options.help) {
-        print_version();
-        print_help(argv[0]);
-        return 0;
-    }
-    if (options.version) {
-        print_version();
-        return 0;
-    }
-    
-    // initialize logger
-    switch (options.logger) {
-        case LOGGER_STDOUT:
-            BLog_InitStdout();
-            break;
-        #ifndef BADVPN_USE_WINAPI
-        case LOGGER_SYSLOG:
-            if (!BLog_InitSyslog(options.logger_syslog_ident, options.logger_syslog_facility)) {
-                fprintf(stderr, "Failed to initialize syslog logger\n");
-                goto fail0;
-            }
-            break;
-        #endif
-        default:
-            ASSERT(0);
-    }
-    
-    // configure logger channels
-    for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
-        if (options.loglevels[i] >= 0) {
-            BLog_SetChannelLoglevel(i, options.loglevels[i]);
-        }
-        else if (options.loglevel >= 0) {
-            BLog_SetChannelLoglevel(i, options.loglevel);
-        }
-    }
-    
-    BLog(BLOG_NOTICE, "initializing "GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION);
-    
-    if (options.ssl) {
-        // init NSPR
-        PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
-        
-        // register local NSPR file types
-        if (!DummyPRFileDesc_GlobalInit()) {
-            BLog(BLOG_ERROR, "DummyPRFileDesc_GlobalInit failed");
-            goto fail01;
-        }
-        if (!BSSLConnection_GlobalInit()) {
-            BLog(BLOG_ERROR, "BSSLConnection_GlobalInit failed");
-            goto fail01;
-        }
-        
-        // init NSS
-        if (NSS_Init(options.nssdb) != SECSuccess) {
-            BLog(BLOG_ERROR, "NSS_Init failed (%d)", (int)PR_GetError());
-            goto fail01;
-        }
-        
-        // set cipher policy
-        if (NSS_SetDomesticPolicy() != SECSuccess) {
-            BLog(BLOG_ERROR, "NSS_SetDomesticPolicy failed (%d)", (int)PR_GetError());
-            goto fail02;
-        }
-        
-        // init server cache
-        if (SSL_ConfigServerSessionIDCache(0, 0, 0, NULL) != SECSuccess) {
-            BLog(BLOG_ERROR, "SSL_ConfigServerSessionIDCache failed (%d)", (int)PR_GetError());
-            goto fail02;
-        }
-        
-        // open server certificate and private key
-        if (!open_nss_cert_and_key(options.client_cert_name, &client_cert, &client_key)) {
-            BLog(BLOG_ERROR, "Cannot open certificate and key");
-            goto fail03;
-        }
-    }
-    
-    // initialize network
-    if (!BNetwork_GlobalInit()) {
-        BLog(BLOG_ERROR, "BNetwork_GlobalInit failed");
-        goto fail1;
-    }
-    
-    // init time
-    BTime_Init();
-    
-    // process arguments
-    if (!process_arguments()) {
-        BLog(BLOG_ERROR, "Failed to process arguments");
-        goto fail1;
-    }
-    
-    // init reactor
-    if (!BReactor_Init(&ss)) {
-        BLog(BLOG_ERROR, "BReactor_Init failed");
-        goto fail1;
-    }
-    
-    // setup signal handler
-    if (!BSignal_Init(&ss, signal_handler, NULL)) {
-        BLog(BLOG_ERROR, "BSignal_Init failed");
-        goto fail2;
-    }
-    
-    // init thread work dispatcher
-    if (!BThreadWorkDispatcher_Init(&twd, &ss, options.threads)) {
-        BLog(BLOG_ERROR, "BThreadWorkDispatcher_Init failed");
-        goto fail3;
-    }
-    
-    // init BSecurity
-    if (BThreadWorkDispatcher_UsingThreads(&twd)) {
-        if (!BSecurity_GlobalInitThreadSafe()) {
-            BLog(BLOG_ERROR, "BSecurity_GlobalInitThreadSafe failed");
-            goto fail4;
-        }
-    }
-    
-    // init listeners
-    int num_listeners = 0;
-    if (options.transport_mode == TRANSPORT_MODE_TCP) {
-        while (num_listeners < num_bind_addrs) {
-            struct bind_addr *addr = &bind_addrs[num_listeners];
-            if (!PasswordListener_Init(&listeners[num_listeners], &ss, &twd, addr->addr, TCP_MAX_PASSWORD_LISTENER_CLIENTS, options.peer_ssl, ssl_flags(), client_cert, client_key)) {
-                BLog(BLOG_ERROR, "PasswordListener_Init failed");
-                goto fail8;
-            }
-            num_listeners++;
-        }
-    }
-    
-    // init device
-    if (!BTap_Init(&device, &ss, options.tapdev, device_error_handler, NULL, 0)) {
-        BLog(BLOG_ERROR, "BTap_Init failed");
-        goto fail8;
-    }
-    
-    // remember device MTU
-    device_mtu = BTap_GetMTU(&device);
-    
-    BLog(BLOG_INFO, "device MTU is %d", device_mtu);
-    
-    // calculate data MTU
-    if (device_mtu > INT_MAX - DATAPROTO_MAX_OVERHEAD) {
-        BLog(BLOG_ERROR, "Device MTU is too large");
-        goto fail9;
-    }
-    data_mtu = DATAPROTO_MAX_OVERHEAD + device_mtu;
-    
-    // init device input
-    if (!DataProtoSource_Init(&device_dpsource, BTap_GetOutput(&device), device_dpsource_handler, NULL, &ss)) {
-        BLog(BLOG_ERROR, "DataProtoSource_Init failed");
-        goto fail9;
-    }
-    
-    // init device output
-    if (!DPReceiveDevice_Init(&device_output_dprd, device_mtu, (DPReceiveDevice_output_func)BTap_Send, &device, &ss, options.send_buffer_relay_size, PEER_RELAY_FLOW_INACTIVITY_TIME)) {
-        BLog(BLOG_ERROR, "DPReceiveDevice_Init failed");
-        goto fail10;
-    }
-    
-    // init peers list
-    LinkedList1_Init(&peers);
-    num_peers = 0;
-    
-    // init frame decider
-    FrameDecider_Init(&frame_decider, options.max_macs, options.max_groups, options.igmp_group_membership_interval, options.igmp_last_member_query_time, &ss);
-    
-    // init relays list
-    LinkedList1_Init(&relays);
-    
-    // init need relay list
-    LinkedList1_Init(&waiting_relay_peers);
-    
-    // start connecting to server
-    if (!ServerConnection_Init(&server, &ss, &twd, server_addr, SC_KEEPALIVE_INTERVAL, SERVER_BUFFER_MIN_PACKETS, options.ssl, ssl_flags(), client_cert, client_key, server_name, NULL,
-                               server_handler_error, server_handler_ready, server_handler_newclient, server_handler_endclient, server_handler_message
-    )) {
-        BLog(BLOG_ERROR, "ServerConnection_Init failed");
-        goto fail11;
-    }
-    
-    // set server not ready
-    server_ready = 0;
-    
-    // set no dying flow
-    dying_server_flow = NULL;
-    
-    // enter event loop
-    BLog(BLOG_NOTICE, "entering event loop");
-    BReactor_Exec(&ss);
-    
-    if (server_ready) {
-        // allow freeing server queue flows
-        PacketPassFairQueue_PrepareFree(&server_queue);
-        
-        // make ServerConnection stop using buffers from peers before they are freed
-        ServerConnection_ReleaseBuffers(&server);
-    }
-    
-    // free peers
-    LinkedList1Node *node;
-    while (node = LinkedList1_GetFirst(&peers)) {
-        struct peer_data *peer = UPPER_OBJECT(node, struct peer_data, list_node);
-        peer_remove(peer, 1);
-    }
-    
-    // free dying server flow
-    if (dying_server_flow) {
-        server_flow_free(dying_server_flow);
-    }
-    
-    if (server_ready) {
-        PacketPassFairQueue_Free(&server_queue);
-    }
-    ServerConnection_Free(&server);
-fail11:
-    FrameDecider_Free(&frame_decider);
-    DPReceiveDevice_Free(&device_output_dprd);
-fail10:
-    DataProtoSource_Free(&device_dpsource);
-fail9:
-    BTap_Free(&device);
-fail8:
-    if (options.transport_mode == TRANSPORT_MODE_TCP) {
-        while (num_listeners-- > 0) {
-            PasswordListener_Free(&listeners[num_listeners]);
-        }
-    }
-    if (BThreadWorkDispatcher_UsingThreads(&twd)) {
-        BSecurity_GlobalFreeThreadSafe();
-    }
-fail4:
-    // NOTE: BThreadWorkDispatcher must be freed before NSPR and stuff
-    BThreadWorkDispatcher_Free(&twd);
-fail3:
-    BSignal_Finish();
-fail2:
-    BReactor_Free(&ss);
-fail1:
-    if (options.ssl) {
-        CERT_DestroyCertificate(client_cert);
-        SECKEY_DestroyPrivateKey(client_key);
-fail03:
-        ASSERT_FORCE(SSL_ShutdownServerSessionIDCache() == SECSuccess)
-fail02:
-        SSL_ClearSessionCache();
-        ASSERT_FORCE(NSS_Shutdown() == SECSuccess)
-fail01:
-        ASSERT_FORCE(PR_Cleanup() == PR_SUCCESS)
-        PL_ArenaFinish();
-    }
-    BLog(BLOG_NOTICE, "exiting");
-    BLog_Free();
-fail0:
-    // finish objects
-    DebugObjectGlobal_Finish();
-    return 1;
-}
-
-void terminate (void)
-{
-    BLog(BLOG_NOTICE, "tearing down");
-    
-    // exit event loop
-    BReactor_Quit(&ss, 0);
-}
-
-void print_help (const char *name)
-{
-    printf(
-        "Usage:\n"
-        "    %s\n"
-        "        [--help]\n"
-        "        [--version]\n"
-        "        [--logger <"LOGGERS_STRING">]\n"
-        #ifndef BADVPN_USE_WINAPI
-        "        (logger=syslog?\n"
-        "            [--syslog-facility <string>]\n"
-        "            [--syslog-ident <string>]\n"
-        "        )\n"
-        #endif
-        "        [--loglevel <0-5/none/error/warning/notice/info/debug>]\n"
-        "        [--channel-loglevel <channel-name> <0-5/none/error/warning/notice/info/debug>] ...\n"
-        "        [--threads <integer>]\n"
-        "        [--use-threads-for-ssl-handshake]\n"
-        "        [--use-threads-for-ssl-data]\n"
-        "        [--ssl --nssdb <string> --client-cert-name <string>]\n"
-        "        [--server-name <string>]\n"
-        "        --server-addr <addr>\n"
-        "        [--tapdev <name>]\n"
-        "        [--scope <scope_name>] ...\n"
-        "        [\n"
-        "            --bind-addr <addr>\n"
-        "            (transport-mode=udp? --num-ports <num>)\n"
-        "            [--ext-addr <addr / {server_reported}:port> <scope_name>] ...\n"
-        "        ] ...\n"
-        "        --transport-mode <udp/tcp>\n"
-        "        (transport-mode=udp?\n"
-        "            --encryption-mode <blowfish/aes/none>\n"
-        "            --hash-mode <md5/sha1/none>\n"
-        "            [--otp <blowfish/aes> <num> <num-warn>]\n"
-        "            [--fragmentation-latency <milliseconds>]\n"
-        "        )\n"
-        "        (transport-mode=tcp?\n"
-        "            (ssl? [--peer-ssl])\n"
-        "            [--peer-tcp-socket-sndbuf <bytes / 0>]\n"
-        "        )\n"
-        "        [--send-buffer-size <num-packets>]\n"
-        "        [--send-buffer-relay-size <num-packets>]\n"
-        "        [--max-macs <num>]\n"
-        "        [--max-groups <num>]\n"
-        "        [--igmp-group-membership-interval <ms>]\n"
-        "        [--igmp-last-member-query-time <ms>]\n"
-        "        [--allow-peer-talk-without-ssl]\n"
-        "        [--max-peers <number>]\n"
-        "Address format is a.b.c.d:port (IPv4) or [addr]:port (IPv6).\n",
-        name
-    );
-}
-
-void print_version (void)
-{
-    printf(GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION"\n"GLOBAL_COPYRIGHT_NOTICE"\n");
-}
-
-int parse_arguments (int argc, char *argv[])
-{
-    if (argc <= 0) {
-        return 0;
-    }
-    
-    options.help = 0;
-    options.version = 0;
-    options.logger = LOGGER_STDOUT;
-    #ifndef BADVPN_USE_WINAPI
-    options.logger_syslog_facility = "daemon";
-    options.logger_syslog_ident = argv[0];
-    #endif
-    options.loglevel = -1;
-    for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
-        options.loglevels[i] = -1;
-    }
-    options.threads = 0;
-    options.use_threads_for_ssl_handshake = 0;
-    options.use_threads_for_ssl_data = 0;
-    options.ssl = 0;
-    options.nssdb = NULL;
-    options.client_cert_name = NULL;
-    options.server_name = NULL;
-    options.server_addr = NULL;
-    options.tapdev = NULL;
-    options.num_scopes = 0;
-    options.num_bind_addrs = 0;
-    options.transport_mode = -1;
-    options.encryption_mode = -1;
-    options.hash_mode = -1;
-    options.otp_mode = SPPROTO_OTP_MODE_NONE;
-    options.fragmentation_latency = PEER_DEFAULT_UDP_FRAGMENTATION_LATENCY;
-    options.peer_ssl = 0;
-    options.peer_tcp_socket_sndbuf = -1;
-    options.send_buffer_size = PEER_DEFAULT_SEND_BUFFER_SIZE;
-    options.send_buffer_relay_size = PEER_DEFAULT_SEND_BUFFER_RELAY_SIZE;
-    options.max_macs = PEER_DEFAULT_MAX_MACS;
-    options.max_groups = PEER_DEFAULT_MAX_GROUPS;
-    options.igmp_group_membership_interval = DEFAULT_IGMP_GROUP_MEMBERSHIP_INTERVAL;
-    options.igmp_last_member_query_time = DEFAULT_IGMP_LAST_MEMBER_QUERY_TIME;
-    options.allow_peer_talk_without_ssl = 0;
-    options.max_peers = DEFAULT_MAX_PEERS;
-    
-    int have_fragmentation_latency = 0;
-    
-    int i;
-    for (i = 1; i < argc; i++) {
-        char *arg = argv[i];
-        if (!strcmp(arg, "--help")) {
-            options.help = 1;
-        }
-        else if (!strcmp(arg, "--version")) {
-            options.version = 1;
-        }
-        else if (!strcmp(arg, "--logger")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            char *arg2 = argv[i + 1];
-            if (!strcmp(arg2, "stdout")) {
-                options.logger = LOGGER_STDOUT;
-            }
-            #ifndef BADVPN_USE_WINAPI
-            else if (!strcmp(arg2, "syslog")) {
-                options.logger = LOGGER_SYSLOG;
-            }
-            #endif
-            else {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        #ifndef BADVPN_USE_WINAPI
-        else if (!strcmp(arg, "--syslog-facility")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.logger_syslog_facility = argv[i + 1];
-            i++;
-        }
-        else if (!strcmp(arg, "--syslog-ident")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.logger_syslog_ident = argv[i + 1];
-            i++;
-        }
-        #endif
-        else if (!strcmp(arg, "--loglevel")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.loglevel = parse_loglevel(argv[i + 1])) < 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--channel-loglevel")) {
-            if (2 >= argc - i) {
-                fprintf(stderr, "%s: requires two arguments\n", arg);
-                return 0;
-            }
-            int channel = BLogGlobal_GetChannelByName(argv[i + 1]);
-            if (channel < 0) {
-                fprintf(stderr, "%s: wrong channel argument\n", arg);
-                return 0;
-            }
-            int loglevel = parse_loglevel(argv[i + 2]);
-            if (loglevel < 0) {
-                fprintf(stderr, "%s: wrong loglevel argument\n", arg);
-                return 0;
-            }
-            options.loglevels[channel] = loglevel;
-            i += 2;
-        }
-        else if (!strcmp(arg, "--threads")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.threads = atoi(argv[i + 1]);
-            i++;
-        }
-        else if (!strcmp(arg, "--use-threads-for-ssl-handshake")) {
-            options.use_threads_for_ssl_handshake = 1;
-        }
-        else if (!strcmp(arg, "--use-threads-for-ssl-data")) {
-            options.use_threads_for_ssl_data = 1;
-        }
-        else if (!strcmp(arg, "--ssl")) {
-            options.ssl = 1;
-        }
-        else if (!strcmp(arg, "--nssdb")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.nssdb = argv[i + 1];
-            i++;
-        }
-        else if (!strcmp(arg, "--client-cert-name")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.client_cert_name = argv[i + 1];
-            i++;
-        }
-        else if (!strcmp(arg, "--server-name")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.server_name = argv[i + 1];
-            i++;
-        }
-        else if (!strcmp(arg, "--server-addr")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.server_addr = argv[i + 1];
-            i++;
-        }
-        else if (!strcmp(arg, "--tapdev")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.tapdev = argv[i + 1];
-            i++;
-        }
-        else if (!strcmp(arg, "--scope")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if (options.num_scopes == MAX_SCOPES) {
-                fprintf(stderr, "%s: too many\n", arg);
-                return 0;
-            }
-            options.scopes[options.num_scopes] = argv[i + 1];
-            options.num_scopes++;
-            i++;
-        }
-        else if (!strcmp(arg, "--bind-addr")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if (options.num_bind_addrs == MAX_BIND_ADDRS) {
-                fprintf(stderr, "%s: too many\n", arg);
-                return 0;
-            }
-            struct bind_addr_option *addr = &options.bind_addrs[options.num_bind_addrs];
-            addr->addr = argv[i + 1];
-            addr->num_ports = -1;
-            addr->num_ext_addrs = 0;
-            options.num_bind_addrs++;
-            i++;
-        }
-        else if (!strcmp(arg, "--num-ports")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if (options.num_bind_addrs == 0) {
-                fprintf(stderr, "%s: must folow --bind-addr\n", arg);
-                return 0;
-            }
-            struct bind_addr_option *addr = &options.bind_addrs[options.num_bind_addrs - 1];
-            if ((addr->num_ports = atoi(argv[i + 1])) < 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--ext-addr")) {
-            if (2 >= argc - i) {
-                fprintf(stderr, "%s: requires two arguments\n", arg);
-                return 0;
-            }
-            if (options.num_bind_addrs == 0) {
-                fprintf(stderr, "%s: must folow --bind-addr\n", arg);
-                return 0;
-            }
-            struct bind_addr_option *addr = &options.bind_addrs[options.num_bind_addrs - 1];
-            if (addr->num_ext_addrs == MAX_EXT_ADDRS) {
-                fprintf(stderr, "%s: too many\n", arg);
-                return 0;
-            }
-            struct ext_addr_option *eaddr = &addr->ext_addrs[addr->num_ext_addrs];
-            eaddr->addr = argv[i + 1];
-            eaddr->scope = argv[i + 2];
-            addr->num_ext_addrs++;
-            i += 2;
-        }
-        else if (!strcmp(arg, "--transport-mode")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            char *arg2 = argv[i + 1];
-            if (!strcmp(arg2, "udp")) {
-                options.transport_mode = TRANSPORT_MODE_UDP;
-            }
-            else if (!strcmp(arg2, "tcp")) {
-                options.transport_mode = TRANSPORT_MODE_TCP;
-            }
-            else {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--encryption-mode")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            char *arg2 = argv[i + 1];
-            if (!strcmp(arg2, "none")) {
-                options.encryption_mode = SPPROTO_ENCRYPTION_MODE_NONE;
-            }
-            else if (!strcmp(arg2, "blowfish")) {
-                options.encryption_mode = BENCRYPTION_CIPHER_BLOWFISH;
-            }
-            else if (!strcmp(arg2, "aes")) {
-                options.encryption_mode = BENCRYPTION_CIPHER_AES;
-            }
-            else {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--hash-mode")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            char *arg2 = argv[i + 1];
-            if (!strcmp(arg2, "none")) {
-                options.hash_mode = SPPROTO_HASH_MODE_NONE;
-            }
-            else if (!strcmp(arg2, "md5")) {
-                options.hash_mode = BHASH_TYPE_MD5;
-            }
-            else if (!strcmp(arg2, "sha1")) {
-                options.hash_mode = BHASH_TYPE_SHA1;
-            }
-            else {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--otp")) {
-            if (3 >= argc - i) {
-                fprintf(stderr, "%s: requires three arguments\n", arg);
-                return 0;
-            }
-            char *otp_mode = argv[i + 1];
-            char *otp_num = argv[i + 2];
-            char *otp_num_warn = argv[i + 3];
-            if (!strcmp(otp_mode, "blowfish")) {
-                options.otp_mode = BENCRYPTION_CIPHER_BLOWFISH;
-            }
-            else if (!strcmp(otp_mode, "aes")) {
-                options.otp_mode = BENCRYPTION_CIPHER_AES;
-            }
-            else {
-                fprintf(stderr, "%s: wrong mode\n", arg);
-                return 0;
-            }
-            if ((options.otp_num = atoi(otp_num)) <= 0) {
-                fprintf(stderr, "%s: wrong num\n", arg);
-                return 0;
-            }
-            options.otp_num_warn = atoi(otp_num_warn);
-            if (options.otp_num_warn <= 0 || options.otp_num_warn > options.otp_num) {
-                fprintf(stderr, "%s: wrong num warn\n", arg);
-                return 0;
-            }
-            i += 3;
-        }
-        else if (!strcmp(arg, "--fragmentation-latency")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.fragmentation_latency = atoi(argv[i + 1]);
-            have_fragmentation_latency = 1;
-            i++;
-        }
-        else if (!strcmp(arg, "--peer-ssl")) {
-            options.peer_ssl = 1;
-        }
-        else if (!strcmp(arg, "--peer-tcp-socket-sndbuf")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.peer_tcp_socket_sndbuf = atoi(argv[i + 1])) < 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--send-buffer-size")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.send_buffer_size = atoi(argv[i + 1])) <= 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--send-buffer-relay-size")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.send_buffer_relay_size = atoi(argv[i + 1])) <= 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--max-macs")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.max_macs = atoi(argv[i + 1])) <= 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--max-groups")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.max_groups = atoi(argv[i + 1])) <= 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--igmp-group-membership-interval")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.igmp_group_membership_interval = atoi(argv[i + 1])) <= 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--igmp-last-member-query-time")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.igmp_last_member_query_time = atoi(argv[i + 1])) <= 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--max-peers")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.max_peers = atoi(argv[i + 1])) <= 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--allow-peer-talk-without-ssl")) {
-            options.allow_peer_talk_without_ssl = 1;
-        }
-        else {
-            fprintf(stderr, "unknown option: %s\n", arg);
-            return 0;
-        }
-    }
-    
-    if (options.help || options.version) {
-        return 1;
-    }
-    
-    if (options.ssl != !!options.nssdb) {
-        fprintf(stderr, "False: --ssl <=> --nssdb\n");
-        return 0;
-    }
-    
-    if (options.ssl != !!options.client_cert_name) {
-        fprintf(stderr, "False: --ssl <=> --client-cert-name\n");
-        return 0;
-    }
-    
-    if (!options.server_addr) {
-        fprintf(stderr, "False: --server-addr\n");
-        return 0;
-    }
-    
-    if (options.transport_mode < 0) {
-        fprintf(stderr, "False: --transport-mode\n");
-        return 0;
-    }
-    
-    if ((options.transport_mode == TRANSPORT_MODE_UDP) != (options.encryption_mode >= 0)) {
-        fprintf(stderr, "False: UDP <=> --encryption-mode\n");
-        return 0;
-    }
-    
-    if ((options.transport_mode == TRANSPORT_MODE_UDP) != (options.hash_mode >= 0)) {
-        fprintf(stderr, "False: UDP <=> --hash-mode\n");
-        return 0;
-    }
-    
-    if (!(!(options.otp_mode != SPPROTO_OTP_MODE_NONE) || (options.transport_mode == TRANSPORT_MODE_UDP))) {
-        fprintf(stderr, "False: --otp => UDP\n");
-        return 0;
-    }
-    
-    if (!(!have_fragmentation_latency || (options.transport_mode == TRANSPORT_MODE_UDP))) {
-        fprintf(stderr, "False: --fragmentation-latency => UDP\n");
-        return 0;
-    }
-    
-    if (!(!options.peer_ssl || (options.ssl && options.transport_mode == TRANSPORT_MODE_TCP))) {
-        fprintf(stderr, "False: --peer-ssl => (--ssl && TCP)\n");
-        return 0;
-    }
-    
-    if (!(!(options.peer_tcp_socket_sndbuf >= 0) || options.transport_mode == TRANSPORT_MODE_TCP)) {
-        fprintf(stderr, "False: --peer-tcp-socket-sndbuf => TCP\n");
-        return 0;
-    }
-    
-    return 1;
-}
-
-int process_arguments (void)
-{
-    // resolve server address
-    ASSERT(options.server_addr)
-    if (!BAddr_Parse(&server_addr, options.server_addr, server_name, sizeof(server_name))) {
-        BLog(BLOG_ERROR, "server addr: BAddr_Parse failed");
-        return 0;
-    }
-    
-    // override server name if requested
-    if (options.server_name) {
-        if (strlen(options.server_name) >= sizeof(server_name)) {
-            BLog(BLOG_ERROR, "server name: too long");
-            return 0;
-        }
-        strcpy(server_name, options.server_name);
-    }
-    
-    // resolve bind addresses and external addresses
-    num_bind_addrs = 0;
-    for (int i = 0; i < options.num_bind_addrs; i++) {
-        struct bind_addr_option *addr = &options.bind_addrs[i];
-        struct bind_addr *out = &bind_addrs[num_bind_addrs];
-        
-        // read addr
-        if (!BAddr_Parse(&out->addr, addr->addr, NULL, 0)) {
-            BLog(BLOG_ERROR, "bind addr: BAddr_Parse failed");
-            return 0;
-        }
-        
-        // read num ports
-        if (options.transport_mode == TRANSPORT_MODE_UDP) {
-            if (addr->num_ports < 0) {
-                BLog(BLOG_ERROR, "bind addr: num ports missing");
-                return 0;
-            }
-            out->num_ports = addr->num_ports;
-        }
-        else if (addr->num_ports >= 0) {
-            BLog(BLOG_ERROR, "bind addr: num ports given, but not using UDP");
-            return 0;
-        }
-        
-        // read ext addrs
-        out->num_ext_addrs = 0;
-        for (int j = 0; j < addr->num_ext_addrs; j++) {
-            struct ext_addr_option *eaddr = &addr->ext_addrs[j];
-            struct ext_addr *eout = &out->ext_addrs[out->num_ext_addrs];
-            
-            // read addr
-            if (string_begins_with(eaddr->addr, "{server_reported}:")) {
-                char *colon = strstr(eaddr->addr, ":");
-                if ((eout->server_reported_port = atoi(colon + 1)) < 0) {
-                    BLog(BLOG_ERROR, "ext addr: wrong port");
-                    return 0;
-                }
-            } else {
-                eout->server_reported_port = -1;
-                if (!BAddr_Parse(&eout->addr, eaddr->addr, NULL, 0)) {
-                    BLog(BLOG_ERROR, "ext addr: BAddr_Parse failed");
-                    return 0;
-                }
-                if (!addr_supported(eout->addr)) {
-                    BLog(BLOG_ERROR, "ext addr: addr_supported failed");
-                    return 0;
-                }
-            }
-            
-            // read scope
-            if (strlen(eaddr->scope) >= sizeof(eout->scope)) {
-                BLog(BLOG_ERROR, "ext addr: too long");
-                return 0;
-            }
-            strcpy(eout->scope, eaddr->scope);
-            
-            out->num_ext_addrs++;
-        }
-        
-        num_bind_addrs++;
-    }
-    
-    // initialize SPProto parameters
-    if (options.transport_mode == TRANSPORT_MODE_UDP) {
-        sp_params.encryption_mode = options.encryption_mode;
-        sp_params.hash_mode = options.hash_mode;
-        sp_params.otp_mode = options.otp_mode;
-        if (options.otp_mode > 0) {
-            sp_params.otp_num = options.otp_num;
-        }
-    }
-    
-    return 1;
-}
-
-int ssl_flags (void)
-{
-    int flags = 0;
-    if (options.use_threads_for_ssl_handshake) {
-        flags |= BSSLCONNECTION_FLAG_THREADWORK_HANDSHAKE;
-    }
-    if (options.use_threads_for_ssl_data) {
-        flags |= BSSLCONNECTION_FLAG_THREADWORK_IO;
-    }
-    return flags;
-}
-
-void signal_handler (void *unused)
-{
-    BLog(BLOG_NOTICE, "termination requested");
-    
-    terminate();
-}
-
-void peer_add (peerid_t id, int flags, const uint8_t *cert, int cert_len)
-{
-    ASSERT(server_ready)
-    ASSERT(num_peers < options.max_peers)
-    ASSERT(!find_peer_by_id(id))
-    ASSERT(id != my_id)
-    ASSERT(cert_len >= 0)
-    ASSERT(cert_len <= SCID_NEWCLIENT_MAX_CERT_LEN)
-    
-    // allocate structure
-    struct peer_data *peer = (struct peer_data *)malloc(sizeof(*peer));
-    if (!peer) {
-        BLog(BLOG_ERROR, "peer %d: failed to allocate memory", (int)id);
-        goto fail0;
-    }
-    
-    // remember id
-    peer->id = id;
-    
-    // remember flags
-    peer->flags = flags;
-    
-    // set no common name
-    peer->common_name = NULL;
-    
-    if (options.ssl) {
-        // remember certificate
-        memcpy(peer->cert, cert, cert_len);
-        peer->cert_len = cert_len;
-        
-        // make sure that CERT_DecodeCertFromPackage will interpretet the input as raw DER and not base64,
-        // in which case following workaroud wouldn't help
-        if (!(cert_len > 0 && (cert[0] & 0x1f) == 0x10)) {
-            peer_log(peer, BLOG_ERROR, "certificate does not look like DER");
-            goto fail1;
-        }
-        
-        // copy the certificate and append it a good load of zero bytes,
-        // hopefully preventing the crappy CERT_DecodeCertFromPackage from crashing
-        // by reading past the of its input
-        uint8_t *certbuf = (uint8_t *)malloc(cert_len + 100);
-        if (!certbuf) {
-            peer_log(peer, BLOG_ERROR, "malloc failed");
-            goto fail1;
-        }
-        memcpy(certbuf, cert, cert_len);
-        memset(certbuf + cert_len, 0, 100);
-        
-        // decode certificate, so we can extract the common name
-        CERTCertificate *nsscert = CERT_DecodeCertFromPackage((char *)certbuf, cert_len);
-        if (!nsscert) {
-            peer_log(peer, BLOG_ERROR, "CERT_DecodeCertFromPackage failed (%d)", PORT_GetError());
-            free(certbuf);
-            goto fail1;
-        }
-        
-        free(certbuf);
-        
-        // remember common name
-        if (!(peer->common_name = CERT_GetCommonName(&nsscert->subject))) {
-            peer_log(peer, BLOG_ERROR, "CERT_GetCommonName failed");
-            CERT_DestroyCertificate(nsscert);
-            goto fail1;
-        }
-        
-        CERT_DestroyCertificate(nsscert);
-    }
-    
-    // init and set init job (must be before initing server flow so we can send)
-    BPending_Init(&peer->job_init, BReactor_PendingGroup(&ss), (BPending_handler)peer_job_init, peer);
-    BPending_Set(&peer->job_init);
-    
-    // init server flow
-    if (!(peer->server_flow = server_flow_init())) {
-        peer_log(peer, BLOG_ERROR, "server_flow_init failed");
-        goto fail2;
-    }
-    
-    if ((peer->flags & SCID_NEWCLIENT_FLAG_SSL) && !options.ssl) {
-        peer_log(peer, BLOG_ERROR, "peer requires talking with SSL, but we're not using SSL!?");
-        goto fail3;
-    }
-    
-    if (options.ssl && !(peer->flags & SCID_NEWCLIENT_FLAG_SSL) && !options.allow_peer_talk_without_ssl) {
-        peer_log(peer, BLOG_ERROR, "peer requires talking without SSL, but we don't allow that");
-        goto fail3;
-    }
-    
-    // choose chat SSL mode
-    int chat_ssl_mode = PEERCHAT_SSL_NONE;
-    if ((peer->flags & SCID_NEWCLIENT_FLAG_SSL)) {
-        chat_ssl_mode = (peer_am_master(peer) ? PEERCHAT_SSL_SERVER : PEERCHAT_SSL_CLIENT);
-    }
-    
-    // init chat
-    if (!PeerChat_Init(&peer->chat, peer->id, chat_ssl_mode, ssl_flags(), client_cert, client_key, peer->cert, peer->cert_len, BReactor_PendingGroup(&ss), &twd, peer,
-        (BLog_logfunc)peer_logfunc,
-        (PeerChat_handler_error)peer_chat_handler_error,
-        (PeerChat_handler_message)peer_chat_handler_message
-    )) {
-        peer_log(peer, BLOG_ERROR, "PeerChat_Init failed");
-        goto fail3;
-    }
-    
-    // set no message
-    peer->chat_send_msg_len = -1;
-    
-    // connect server flow to chat
-    server_flow_connect(peer->server_flow, PeerChat_GetSendOutput(&peer->chat));
-    
-    // set have chat
-    peer->have_chat = 1;
-    
-    // set have no resetpeer
-    peer->have_resetpeer = 0;
-    
-    // init local flow
-    if (!DataProtoFlow_Init(&peer->local_dpflow, &device_dpsource, my_id, peer->id, options.send_buffer_size, -1, NULL, NULL)) {
-        peer_log(peer, BLOG_ERROR, "DataProtoFlow_Init failed");
-        goto fail4;
-    }
-    
-    // init frame decider peer
-    if (!FrameDeciderPeer_Init(&peer->decider_peer, &frame_decider, peer, (BLog_logfunc)peer_logfunc)) {
-        peer_log(peer, BLOG_ERROR, "FrameDeciderPeer_Init failed");
-        goto fail5;
-    }
-    
-    // init receive peer
-    DPReceivePeer_Init(&peer->receive_peer, &device_output_dprd, peer->id, &peer->decider_peer, !!(peer->flags & SCID_NEWCLIENT_FLAG_RELAY_CLIENT));
-    
-    // have no link
-    peer->have_link = 0;
-    
-    // have no relaying
-    peer->relaying_peer = NULL;
-    
-    // not waiting for relay
-    peer->waiting_relay = 0;
-    
-    // init reset timer
-    BTimer_Init(&peer->reset_timer, PEER_RETRY_TIME, (BTimer_handler)peer_reset_timer_handler, peer);
-    
-    // is not relay server
-    peer->is_relay = 0;
-    
-    // init binding
-    peer->binding = 0;
-    
-    // add to peers list
-    LinkedList1_Append(&peers, &peer->list_node);
-    num_peers++;
-    
-    switch (chat_ssl_mode) {
-        case PEERCHAT_SSL_NONE:
-            peer_log(peer, BLOG_INFO, "initialized; talking to peer in plaintext mode");
-            break;
-        case PEERCHAT_SSL_CLIENT:
-            peer_log(peer, BLOG_INFO, "initialized; talking to peer in SSL client mode");
-            break;
-        case PEERCHAT_SSL_SERVER:
-            peer_log(peer, BLOG_INFO, "initialized; talking to peer in SSL server mode");
-            break;
-    }
-    
-    return;
-    
-fail5:
-    DataProtoFlow_Free(&peer->local_dpflow);
-fail4:
-    server_flow_disconnect(peer->server_flow);
-    PeerChat_Free(&peer->chat);
-fail3:
-    server_flow_free(peer->server_flow);
-fail2:
-    BPending_Free(&peer->job_init);
-    if (peer->common_name) {
-        PORT_Free(peer->common_name);
-    }
-fail1:
-    free(peer);
-fail0:
-    return;
-}
-
-void peer_remove (struct peer_data *peer, int exiting)
-{
-    peer_log(peer, BLOG_INFO, "removing");
-    
-    // cleanup connections
-    peer_cleanup_connections(peer);
-    
-    ASSERT(!peer->have_link)
-    ASSERT(!peer->relaying_peer)
-    ASSERT(!peer->waiting_relay)
-    ASSERT(!peer->is_relay)
-    
-    // remove from peers list
-    LinkedList1_Remove(&peers, &peer->list_node);
-    num_peers--;
-    
-    // free reset timer
-    BReactor_RemoveTimer(&ss, &peer->reset_timer);
-    
-    // free receive peer
-    DPReceivePeer_Free(&peer->receive_peer);
-    
-    // free frame decider
-    FrameDeciderPeer_Free(&peer->decider_peer);
-    
-    // free local flow
-    DataProtoFlow_Free(&peer->local_dpflow);
-    
-    // free chat
-    if (peer->have_chat) {
-        peer_free_chat(peer);
-    }
-    
-    // free resetpeer
-    if (peer->have_resetpeer) {
-        // disconnect resetpeer source from server flow
-        server_flow_disconnect(peer->server_flow);
-        
-        // free resetpeer source
-        SinglePacketSource_Free(&peer->resetpeer_source);
-    }
-    
-    // free/die server flow
-    if (exiting || !PacketPassFairQueueFlow_IsBusy(&peer->server_flow->qflow)) {
-        server_flow_free(peer->server_flow);
-    } else {
-        server_flow_die(peer->server_flow);
-    }
-    
-    // free jobs
-    BPending_Free(&peer->job_init);
-    
-    // free common name
-    if (peer->common_name) {
-        PORT_Free(peer->common_name);
-    }
-    
-    // free peer structure
-    free(peer);
-}
-
-void peer_logfunc (struct peer_data *peer)
-{
-    BLog_Append("peer %d", (int)peer->id);
-    if (peer->common_name) {
-        BLog_Append(" (%s)", peer->common_name);
-    }
-    BLog_Append(": ");
-}
-
-void peer_log (struct peer_data *peer, int level, const char *fmt, ...)
-{
-    va_list vl;
-    va_start(vl, fmt);
-    BLog_LogViaFuncVarArg((BLog_logfunc)peer_logfunc, peer, BLOG_CURRENT_CHANNEL, level, fmt, vl);
-    va_end(vl);
-}
-
-int peer_am_master (struct peer_data *peer)
-{
-    return (my_id > peer->id);
-}
-
-void peer_free_chat (struct peer_data *peer)
-{
-    ASSERT(peer->have_chat)
-    
-    // disconnect chat from server flow
-    server_flow_disconnect(peer->server_flow);
-    
-    // free chat
-    PeerChat_Free(&peer->chat);
-    
-    // set have no chat
-    peer->have_chat = 0;
-}
-
-int peer_init_link (struct peer_data *peer)
-{
-    ASSERT(!peer->have_link)
-    ASSERT(!peer->relaying_peer)
-    ASSERT(!peer->waiting_relay)
-    
-    ASSERT(!peer->is_relay)
-    
-    // init receive receiver
-    DPReceiveReceiver_Init(&peer->receive_receiver, &peer->receive_peer);
-    PacketPassInterface *recv_if = DPReceiveReceiver_GetInput(&peer->receive_receiver);
-    
-    // init transport-specific link objects
-    PacketPassInterface *link_if;
-    if (options.transport_mode == TRANSPORT_MODE_UDP) {
-        // init DatagramPeerIO
-        if (!DatagramPeerIO_Init(
-            &peer->pio.udp.pio, &ss, data_mtu, CLIENT_UDP_MTU, sp_params,
-            options.fragmentation_latency, PEER_UDP_ASSEMBLER_NUM_FRAMES, recv_if,
-            options.otp_num_warn, &twd, peer,
-            (BLog_logfunc)peer_logfunc,
-            (DatagramPeerIO_handler_error)peer_udp_pio_handler_error,
-            (DatagramPeerIO_handler_otp_warning)peer_udp_pio_handler_seed_warning,
-            (DatagramPeerIO_handler_otp_ready)peer_udp_pio_handler_seed_ready
-        )) {
-            peer_log(peer, BLOG_ERROR, "DatagramPeerIO_Init failed");
-            goto fail1;
-        }
-        
-        if (SPPROTO_HAVE_OTP(sp_params)) {
-            // init send seed state
-            peer->pio.udp.sendseed_nextid = 0;
-            peer->pio.udp.sendseed_sent = 0;
-            
-            // init send seed job
-            BPending_Init(&peer->pio.udp.job_send_seed, BReactor_PendingGroup(&ss), (BPending_handler)peer_job_send_seed, peer);
-        }
-        
-        link_if = DatagramPeerIO_GetSendInput(&peer->pio.udp.pio);
-    } else {
-        // init StreamPeerIO
-        if (!StreamPeerIO_Init(
-            &peer->pio.tcp.pio, &ss, &twd, options.peer_ssl, ssl_flags(),
-            (options.peer_ssl ? peer->cert : NULL),
-            (options.peer_ssl ? peer->cert_len : -1),
-            data_mtu,
-            (options.peer_tcp_socket_sndbuf >= 0 ? options.peer_tcp_socket_sndbuf : PEER_DEFAULT_TCP_SOCKET_SNDBUF),
-            recv_if,
-            (BLog_logfunc)peer_logfunc,
-            (StreamPeerIO_handler_error)peer_tcp_pio_handler_error, peer
-        )) {
-            peer_log(peer, BLOG_ERROR, "StreamPeerIO_Init failed");
-            goto fail1;
-        }
-        
-        link_if = StreamPeerIO_GetSendInput(&peer->pio.tcp.pio);
-    }
-    
-    // init sending
-    if (!DataProtoSink_Init(&peer->send_dp, &ss, link_if, PEER_KEEPALIVE_INTERVAL, PEER_KEEPALIVE_RECEIVE_TIMER, (DataProtoSink_handler)peer_dataproto_handler, peer)) {
-        peer_log(peer, BLOG_ERROR, "DataProto_Init failed");
-        goto fail2;
-    }
-    
-    // attach local flow to our DataProtoSink
-    DataProtoFlow_Attach(&peer->local_dpflow, &peer->send_dp);
-    
-    // attach receive peer to our DataProtoSink
-    DPReceivePeer_AttachSink(&peer->receive_peer, &peer->send_dp);
-    
-    // set have link
-    peer->have_link = 1;
-    
-    return 1;
-    
-fail2:
-    if (options.transport_mode == TRANSPORT_MODE_UDP) {
-        if (SPPROTO_HAVE_OTP(sp_params)) {
-            BPending_Free(&peer->pio.udp.job_send_seed);
-        }
-        DatagramPeerIO_Free(&peer->pio.udp.pio);
-    } else {
-        StreamPeerIO_Free(&peer->pio.tcp.pio);
-    }
-fail1:
-    DPReceiveReceiver_Free(&peer->receive_receiver);
-    return 0;
-}
-
-void peer_free_link (struct peer_data *peer)
-{
-    ASSERT(peer->have_link)
-    ASSERT(!peer->is_relay)
-    
-    ASSERT(!peer->relaying_peer)
-    ASSERT(!peer->waiting_relay)
-    
-    // detach receive peer from our DataProtoSink
-    DPReceivePeer_DetachSink(&peer->receive_peer);
-    
-    // detach local flow from our DataProtoSink
-    DataProtoFlow_Detach(&peer->local_dpflow);
-    
-    // free sending
-    DataProtoSink_Free(&peer->send_dp);
-    
-    // free transport-specific link objects
-    if (options.transport_mode == TRANSPORT_MODE_UDP) {
-        if (SPPROTO_HAVE_OTP(sp_params)) {
-            BPending_Free(&peer->pio.udp.job_send_seed);
-        }
-        DatagramPeerIO_Free(&peer->pio.udp.pio);
-    } else {
-        StreamPeerIO_Free(&peer->pio.tcp.pio);
-    }
-    
-    // free receive receiver
-    DPReceiveReceiver_Free(&peer->receive_receiver);
-    
-    // set have no link
-    peer->have_link = 0;
-}
-
-void peer_cleanup_connections (struct peer_data *peer)
-{
-    if (peer->have_link) {
-        if (peer->is_relay) {
-            peer_disable_relay_provider(peer);
-        }
-        peer_free_link(peer);
-    }
-    else if (peer->relaying_peer) {
-        peer_free_relaying(peer);
-    }
-    else if (peer->waiting_relay) {
-        peer_unregister_need_relay(peer);
-    }
-    
-    ASSERT(!peer->have_link)
-    ASSERT(!peer->relaying_peer)
-    ASSERT(!peer->waiting_relay)
-    ASSERT(!peer->is_relay)
-}
-
-void peer_enable_relay_provider (struct peer_data *peer)
-{
-    ASSERT(peer->have_link)
-    ASSERT(!peer->is_relay)
-    
-    ASSERT(!peer->relaying_peer)
-    ASSERT(!peer->waiting_relay)
-    
-    // add to relays list
-    LinkedList1_Append(&relays, &peer->relay_list_node);
-    
-    // init users list
-    LinkedList1_Init(&peer->relay_users);
-    
-    // set is relay
-    peer->is_relay = 1;
-    
-    // assign relays
-    assign_relays();
-}
-
-void peer_disable_relay_provider (struct peer_data *peer)
-{
-    ASSERT(peer->is_relay)
-    
-    ASSERT(peer->have_link)
-    ASSERT(!peer->relaying_peer)
-    ASSERT(!peer->waiting_relay)
-    
-    // disconnect relay users
-    LinkedList1Node *list_node;
-    while (list_node = LinkedList1_GetFirst(&peer->relay_users)) {
-        struct peer_data *relay_user = UPPER_OBJECT(list_node, struct peer_data, relaying_list_node);
-        ASSERT(relay_user->relaying_peer == peer)
-        
-        // disconnect relay user
-        peer_free_relaying(relay_user);
-        
-        // add it to need relay list
-        peer_register_need_relay(relay_user);
-    }
-    
-    // remove from relays list
-    LinkedList1_Remove(&relays, &peer->relay_list_node);
-    
-    // set is not relay
-    peer->is_relay = 0;
-    
-    // assign relays
-    assign_relays();
-}
-
-void peer_install_relaying (struct peer_data *peer, struct peer_data *relay)
-{
-    ASSERT(!peer->relaying_peer)
-    ASSERT(!peer->have_link)
-    ASSERT(!peer->waiting_relay)
-    ASSERT(relay->is_relay)
-    
-    ASSERT(!peer->is_relay)
-    ASSERT(relay->have_link)
-    
-    peer_log(peer, BLOG_INFO, "installing relaying through %d", (int)relay->id);
-    
-    // add to relay's users list
-    LinkedList1_Append(&relay->relay_users, &peer->relaying_list_node);
-    
-    // attach local flow to relay
-    DataProtoFlow_Attach(&peer->local_dpflow, &relay->send_dp);
-    
-    // set relaying
-    peer->relaying_peer = relay;
-}
-
-void peer_free_relaying (struct peer_data *peer)
-{
-    ASSERT(peer->relaying_peer)
-    
-    ASSERT(!peer->have_link)
-    ASSERT(!peer->waiting_relay)
-    
-    struct peer_data *relay = peer->relaying_peer;
-    ASSERT(relay->is_relay)
-    ASSERT(relay->have_link)
-    
-    peer_log(peer, BLOG_INFO, "uninstalling relaying through %d", (int)relay->id);
-    
-    // detach local flow from relay
-    DataProtoFlow_Detach(&peer->local_dpflow);
-    
-    // remove from relay's users list
-    LinkedList1_Remove(&relay->relay_users, &peer->relaying_list_node);
-    
-    // set not relaying
-    peer->relaying_peer = NULL;
-}
-
-void peer_need_relay (struct peer_data *peer)
-{
-    ASSERT(!peer->is_relay)
-    
-    if (peer->waiting_relay) {
-        // already waiting for relay, do nothing
-        return;
-    }
-    
-    if (peer->have_link) {
-        peer_free_link(peer);
-    }
-    else if (peer->relaying_peer) {
-        peer_free_relaying(peer);
-    }
-    
-    // register the peer as needing a relay
-    peer_register_need_relay(peer);
-    
-    // assign relays
-    assign_relays();
-}
-
-void peer_register_need_relay (struct peer_data *peer)
-{
-    ASSERT(!peer->waiting_relay)
-    ASSERT(!peer->have_link)
-    ASSERT(!peer->relaying_peer)
-    
-    ASSERT(!peer->is_relay)
-    
-    // add to need relay list
-    LinkedList1_Append(&waiting_relay_peers, &peer->waiting_relay_list_node);
-    
-    // set waiting relay
-    peer->waiting_relay = 1;
-}
-
-void peer_unregister_need_relay (struct peer_data *peer)
-{
-    ASSERT(peer->waiting_relay)
-    
-    ASSERT(!peer->have_link)
-    ASSERT(!peer->relaying_peer)
-    ASSERT(!peer->is_relay)
-    
-    // remove from need relay list
-    LinkedList1_Remove(&waiting_relay_peers, &peer->waiting_relay_list_node);
-    
-    // set not waiting relay
-    peer->waiting_relay = 0;
-}
-
-void peer_reset (struct peer_data *peer)
-{
-    peer_log(peer, BLOG_NOTICE, "resetting");
-    
-    // cleanup connections
-    peer_cleanup_connections(peer);
-    
-    if (peer_am_master(peer)) {
-        // if we're the master, schedule retry
-        BReactor_SetTimer(&ss, &peer->reset_timer);
-    } else {
-        // if we're the slave, report to master
-        peer_send_simple(peer, MSGID_YOURETRY);
-    }
-}
-
-void peer_resetpeer (struct peer_data *peer)
-{
-    ASSERT(peer->have_chat)
-    ASSERT(!peer->have_resetpeer)
-    
-    // free chat
-    peer_free_chat(peer);
-    
-    // build resetpeer packet
-    struct packetproto_header pp_header;
-    struct sc_header sc_header;
-    struct sc_client_resetpeer sc_resetpeer;
-    pp_header.len = htol16(sizeof(struct sc_header) + sizeof(struct sc_client_resetpeer));
-    sc_header.type = htol8(SCID_RESETPEER);
-    sc_resetpeer.clientid = htol16(peer->id);
-    memcpy(peer->resetpeer_packet, &pp_header, sizeof(pp_header));
-    memcpy(peer->resetpeer_packet + sizeof(pp_header), &sc_header, sizeof(sc_header));
-    memcpy(peer->resetpeer_packet + sizeof(pp_header) + sizeof(sc_header), &sc_resetpeer, sizeof(sc_resetpeer));
-    
-    // init resetpeer sourse
-    SinglePacketSource_Init(&peer->resetpeer_source, peer->resetpeer_packet, sizeof(peer->resetpeer_packet), BReactor_PendingGroup(&ss));
-    
-    // connect server flow to resetpeer source
-    server_flow_connect(peer->server_flow, SinglePacketSource_GetOutput(&peer->resetpeer_source));
-    
-    // set have resetpeer
-    peer->have_resetpeer = 1;
-}
-
-void peer_chat_handler_error (struct peer_data *peer)
-{
-    ASSERT(peer->have_chat)
-    ASSERT(!peer->have_resetpeer)
-    
-    peer_log(peer, BLOG_ERROR, "chat error, sending resetpeer");
-    
-    peer_resetpeer(peer);
-}
-
-void peer_chat_handler_message (struct peer_data *peer, uint8_t *data, int data_len)
-{
-    ASSERT(peer->have_chat)
-    ASSERT(data_len >= 0)
-    ASSERT(data_len <= SC_MAX_MSGLEN)
-    
-    // parse message
-    msgParser parser;
-    if (!msgParser_Init(&parser, data, data_len)) {
-        peer_log(peer, BLOG_NOTICE, "msg: failed to parse");
-        return;
-    }
-    
-    // read message
-    uint16_t type = 0; // to remove warning
-    ASSERT_EXECUTE(msgParser_Gettype(&parser, &type))
-    uint8_t *payload = NULL; // to remove warning
-    int payload_len = 0; // to remove warning
-    ASSERT_EXECUTE(msgParser_Getpayload(&parser, &payload, &payload_len))
-    
-    // dispatch according to message type
-    switch (type) {
-        case MSGID_YOUCONNECT:
-            peer_msg_youconnect(peer, payload, payload_len);
-            return;
-        case MSGID_CANNOTCONNECT:
-            peer_msg_cannotconnect(peer, payload, payload_len);
-            return;
-        case MSGID_CANNOTBIND:
-            peer_msg_cannotbind(peer, payload, payload_len);
-            return;
-        case MSGID_YOURETRY:
-            peer_msg_youretry(peer, payload, payload_len);
-            return;
-        case MSGID_SEED:
-            peer_msg_seed(peer, payload, payload_len);
-            return;
-        case MSGID_CONFIRMSEED:
-            peer_msg_confirmseed(peer, payload, payload_len);
-            return;
-        default:
-            BLog(BLOG_NOTICE, "msg: unknown type");
-            return;
-    }
-}
-
-void peer_msg_youconnect (struct peer_data *peer, uint8_t *data, int data_len)
-{
-    // init parser
-    msg_youconnectParser parser;
-    if (!msg_youconnectParser_Init(&parser, data, data_len)) {
-        peer_log(peer, BLOG_WARNING, "msg_youconnect: failed to parse");
-        return;
-    }
-    
-    // try addresses
-    BAddr addr;
-    while (1) {
-        // get address message
-        uint8_t *addrmsg_data;
-        int addrmsg_len;
-        if (!msg_youconnectParser_Getaddr(&parser, &addrmsg_data, &addrmsg_len)) {
-            peer_log(peer, BLOG_NOTICE, "msg_youconnect: no usable addresses");
-            peer_send_simple(peer, MSGID_CANNOTCONNECT);
-            return;
-        }
-        
-        // parse address message
-        msg_youconnect_addrParser aparser;
-        if (!msg_youconnect_addrParser_Init(&aparser, addrmsg_data, addrmsg_len)) {
-            peer_log(peer, BLOG_WARNING, "msg_youconnect: failed to parse address message");
-            return;
-        }
-        
-        // check if the address scope is known
-        uint8_t *name_data = NULL; // to remove warning
-        int name_len = 0; // to remove warning
-        ASSERT_EXECUTE(msg_youconnect_addrParser_Getname(&aparser, &name_data, &name_len))
-        char *name;
-        if (!(name = address_scope_known(name_data, name_len))) {
-            continue;
-        }
-        
-        // read address
-        uint8_t *addr_data = NULL; // to remove warning
-        int addr_len = 0; // to remove warning
-        ASSERT_EXECUTE(msg_youconnect_addrParser_Getaddr(&aparser, &addr_data, &addr_len))
-        if (!addr_read(addr_data, addr_len, &addr)) {
-            peer_log(peer, BLOG_WARNING, "msg_youconnect: failed to read address");
-            continue;
-        }
-        
-        peer_log(peer, BLOG_NOTICE, "msg_youconnect: using address in scope '%s'", name);
-        break;
-    }
-    
-    // discard further addresses
-    msg_youconnectParser_Forwardaddr(&parser);
-    
-    uint8_t *key = NULL;
-    uint64_t password = 0;
-    
-    // read additonal parameters
-    if (options.transport_mode == TRANSPORT_MODE_UDP) {
-        if (SPPROTO_HAVE_ENCRYPTION(sp_params)) {
-            int key_len;
-            if (!msg_youconnectParser_Getkey(&parser, &key, &key_len)) {
-                peer_log(peer, BLOG_WARNING, "msg_youconnect: no key");
-                return;
-            }
-            if (key_len != BEncryption_cipher_key_size(sp_params.encryption_mode)) {
-                peer_log(peer, BLOG_WARNING, "msg_youconnect: wrong key size");
-                return;
-            }
-        }
-    } else {
-        if (!msg_youconnectParser_Getpassword(&parser, &password)) {
-            peer_log(peer, BLOG_WARNING, "msg_youconnect: no password");
-            return;
-        }
-    }
-    
-    if (!msg_youconnectParser_GotEverything(&parser)) {
-        peer_log(peer, BLOG_WARNING, "msg_youconnect: stray data");
-        return;
-    }
-    
-    peer_log(peer, BLOG_INFO, "connecting");
-    
-    peer_connect(peer, addr, key, password);
-}
-
-void peer_msg_cannotconnect (struct peer_data *peer, uint8_t *data, int data_len)
-{
-    if (data_len != 0) {
-        peer_log(peer, BLOG_WARNING, "msg_cannotconnect: invalid length");
-        return;
-    }
-    
-    if (!peer->binding) {
-        peer_log(peer, BLOG_WARNING, "msg_cannotconnect: not binding");
-        return;
-    }
-    
-    peer_log(peer, BLOG_INFO, "peer could not connect");
-    
-    // continue trying bind addresses
-    peer_bind(peer);
-    return;
-}
-
-void peer_msg_cannotbind (struct peer_data *peer, uint8_t *data, int data_len)
-{
-    if (data_len != 0) {
-        peer_log(peer, BLOG_WARNING, "msg_cannotbind: invalid length");
-        return;
-    }
-    
-    peer_log(peer, BLOG_INFO, "peer cannot bind");
-    
-    if (!peer_am_master(peer)) {
-        peer_start_binding(peer);
-    } else {
-        if (!peer->is_relay) {
-            peer_need_relay(peer);
-        }
-    }
-}
-
-void peer_msg_seed (struct peer_data *peer, uint8_t *data, int data_len)
-{
-    msg_seedParser parser;
-    if (!msg_seedParser_Init(&parser, data, data_len)) {
-        peer_log(peer, BLOG_WARNING, "msg_seed: failed to parse");
-        return;
-    }
-    
-    // read message
-    uint16_t seed_id = 0; // to remove warning
-    ASSERT_EXECUTE(msg_seedParser_Getseed_id(&parser, &seed_id))
-    uint8_t *key = NULL; // to remove warning
-    int key_len = 0; // to remove warning
-    ASSERT_EXECUTE(msg_seedParser_Getkey(&parser, &key, &key_len))
-    uint8_t *iv = NULL; // to remove warning
-    int iv_len = 0; // to remove warning
-    ASSERT_EXECUTE(msg_seedParser_Getiv(&parser, &iv, &iv_len))
-    
-    if (options.transport_mode != TRANSPORT_MODE_UDP) {
-        peer_log(peer, BLOG_WARNING, "msg_seed: not in UDP mode");
-        return;
-    }
-    
-    if (!SPPROTO_HAVE_OTP(sp_params)) {
-        peer_log(peer, BLOG_WARNING, "msg_seed: OTPs disabled");
-        return;
-    }
-    
-    if (key_len != BEncryption_cipher_key_size(sp_params.otp_mode)) {
-        peer_log(peer, BLOG_WARNING, "msg_seed: wrong key length");
-        return;
-    }
-    
-    if (iv_len != BEncryption_cipher_block_size(sp_params.otp_mode)) {
-        peer_log(peer, BLOG_WARNING, "msg_seed: wrong IV length");
-        return;
-    }
-    
-    if (!peer->have_link) {
-        peer_log(peer, BLOG_WARNING, "msg_seed: have no link");
-        return;
-    }
-    
-    peer_log(peer, BLOG_DEBUG, "received OTP receive seed");
-    
-    // add receive seed
-    DatagramPeerIO_AddOTPRecvSeed(&peer->pio.udp.pio, seed_id, key, iv);
-    
-    // remember seed ID so we can confirm it from peer_udp_pio_handler_seed_ready
-    peer->pio.udp.pending_recvseed_id = seed_id;
-}
-
-void peer_msg_confirmseed (struct peer_data *peer, uint8_t *data, int data_len)
-{
-    msg_confirmseedParser parser;
-    if (!msg_confirmseedParser_Init(&parser, data, data_len)) {
-        peer_log(peer, BLOG_WARNING, "msg_confirmseed: failed to parse");
-        return;
-    }
-    
-    // read message
-    uint16_t seed_id = 0; // to remove warning
-    ASSERT_EXECUTE(msg_confirmseedParser_Getseed_id(&parser, &seed_id))
-    
-    if (options.transport_mode != TRANSPORT_MODE_UDP) {
-        peer_log(peer, BLOG_WARNING, "msg_confirmseed: not in UDP mode");
-        return;
-    }
-    
-    if (!SPPROTO_HAVE_OTP(sp_params)) {
-        peer_log(peer, BLOG_WARNING, "msg_confirmseed: OTPs disabled");
-        return;
-    }
-    
-    if (!peer->have_link) {
-        peer_log(peer, BLOG_WARNING, "msg_confirmseed: have no link");
-        return;
-    }
-    
-    if (!peer->pio.udp.sendseed_sent) {
-        peer_log(peer, BLOG_WARNING, "msg_confirmseed: no seed has been sent");
-        return;
-    }
-    
-    if (seed_id != peer->pio.udp.sendseed_sent_id) {
-        peer_log(peer, BLOG_WARNING, "msg_confirmseed: invalid seed: expecting %d, received %d", (int)peer->pio.udp.sendseed_sent_id, (int)seed_id);
-        return;
-    }
-    
-    peer_log(peer, BLOG_DEBUG, "OTP send seed confirmed");
-    
-    // no longer waiting for confirmation
-    peer->pio.udp.sendseed_sent = 0;
-    
-    // start using the seed
-    DatagramPeerIO_SetOTPSendSeed(&peer->pio.udp.pio, peer->pio.udp.sendseed_sent_id, peer->pio.udp.sendseed_sent_key, peer->pio.udp.sendseed_sent_iv);
-}
-
-void peer_msg_youretry (struct peer_data *peer, uint8_t *data, int data_len)
-{
-    if (data_len != 0) {
-        peer_log(peer, BLOG_WARNING, "msg_youretry: invalid length");
-        return;
-    }
-    
-    if (!peer_am_master(peer)) {
-        peer_log(peer, BLOG_WARNING, "msg_youretry: we are not master");
-        return;
-    }
-    
-    peer_log(peer, BLOG_NOTICE, "requests reset");
-    
-    peer_reset(peer);
-}
-
-void peer_udp_pio_handler_seed_warning (struct peer_data *peer)
-{
-    ASSERT(options.transport_mode == TRANSPORT_MODE_UDP)
-    ASSERT(SPPROTO_HAVE_OTP(sp_params))
-    ASSERT(peer->have_link)
-    
-    // generate and send a new seed
-    if (!peer->pio.udp.sendseed_sent) {
-        BPending_Set(&peer->pio.udp.job_send_seed);
-    }
-}
-
-void peer_udp_pio_handler_seed_ready (struct peer_data *peer)
-{
-    ASSERT(options.transport_mode == TRANSPORT_MODE_UDP)
-    ASSERT(SPPROTO_HAVE_OTP(sp_params))
-    ASSERT(peer->have_link)
-    
-    // send confirmation
-    peer_send_confirmseed(peer, peer->pio.udp.pending_recvseed_id);
-}
-
-void peer_udp_pio_handler_error (struct peer_data *peer)
-{
-    ASSERT(options.transport_mode == TRANSPORT_MODE_UDP)
-    ASSERT(peer->have_link)
-    
-    peer_log(peer, BLOG_NOTICE, "UDP connection failed");
-    
-    peer_reset(peer);
-    return;
-}
-
-void peer_tcp_pio_handler_error (struct peer_data *peer)
-{
-    ASSERT(options.transport_mode == TRANSPORT_MODE_TCP)
-    ASSERT(peer->have_link)
-    
-    peer_log(peer, BLOG_NOTICE, "TCP connection failed");
-    
-    peer_reset(peer);
-    return;
-}
-
-void peer_reset_timer_handler (struct peer_data *peer)
-{
-    ASSERT(peer_am_master(peer))
-    
-    BLog(BLOG_NOTICE, "retry timer expired");
-    
-    // start setup process
-    peer_start_binding(peer);
-}
-
-void peer_start_binding (struct peer_data *peer)
-{
-    peer->binding = 1;
-    peer->binding_addrpos = 0;
-    
-    peer_bind(peer);
-}
-
-void peer_bind (struct peer_data *peer)
-{
-    ASSERT(peer->binding)
-    ASSERT(peer->binding_addrpos >= 0)
-    ASSERT(peer->binding_addrpos <= num_bind_addrs)
-    
-    while (peer->binding_addrpos < num_bind_addrs) {
-        // if there are no external addresses, skip bind address
-        if (bind_addrs[peer->binding_addrpos].num_ext_addrs == 0) {
-            peer->binding_addrpos++;
-            continue;
-        }
-        
-        // try to bind
-        int cont;
-        peer_bind_one_address(peer, peer->binding_addrpos, &cont);
-        
-        // increment address counter
-        peer->binding_addrpos++;
-        
-        if (!cont) {
-            return;
-        }
-    }
-    
-    peer_log(peer, BLOG_NOTICE, "no more addresses to bind to");
-    
-    // no longer binding
-    peer->binding = 0;
-    
-    // tell the peer we failed to bind
-    peer_send_simple(peer, MSGID_CANNOTBIND);
-    
-    // if we are the slave, setup relaying
-    if (!peer_am_master(peer)) {
-        if (!peer->is_relay) {
-            peer_need_relay(peer);
-        }
-    }
-}
-
-void peer_bind_one_address (struct peer_data *peer, int addr_index, int *cont)
-{
-    ASSERT(addr_index >= 0)
-    ASSERT(addr_index < num_bind_addrs)
-    ASSERT(bind_addrs[addr_index].num_ext_addrs > 0)
-    
-    // get a fresh link
-    peer_cleanup_connections(peer);
-    if (!peer_init_link(peer)) {
-        peer_log(peer, BLOG_ERROR, "cannot get link");
-        *cont = 0;
-        peer_reset(peer);
-        return;
-    }
-    
-    if (options.transport_mode == TRANSPORT_MODE_UDP) {
-        // get addr
-        struct bind_addr *addr = &bind_addrs[addr_index];
-        
-        // try binding to all ports in the range
-        int port_add;
-        for (port_add = 0; port_add < addr->num_ports; port_add++) {
-            BAddr tryaddr = addr->addr;
-            BAddr_SetPort(&tryaddr, hton16(ntoh16(BAddr_GetPort(&tryaddr)) + port_add));
-            if (DatagramPeerIO_Bind(&peer->pio.udp.pio, tryaddr)) {
-                break;
-            }
-        }
-        if (port_add == addr->num_ports) {
-            BLog(BLOG_NOTICE, "failed to bind to any port");
-            *cont = 1;
-            return;
-        }
-        
-        uint8_t key[BENCRYPTION_MAX_KEY_SIZE];
-        
-        // generate and set encryption key
-        if (SPPROTO_HAVE_ENCRYPTION(sp_params)) {
-            BRandom_randomize(key, BEncryption_cipher_key_size(sp_params.encryption_mode));
-            DatagramPeerIO_SetEncryptionKey(&peer->pio.udp.pio, key);
-        }
-        
-        // schedule sending OTP seed
-        if (SPPROTO_HAVE_OTP(sp_params)) {
-            BPending_Set(&peer->pio.udp.job_send_seed);
-        }
-        
-        // send connectinfo
-        peer_send_conectinfo(peer, addr_index, port_add, key, 0);
-    } else {
-        // order StreamPeerIO to listen
-        uint64_t pass;
-        StreamPeerIO_Listen(&peer->pio.tcp.pio, &listeners[addr_index], &pass);
-        
-        // send connectinfo
-        peer_send_conectinfo(peer, addr_index, 0, NULL, pass);
-    }
-    
-    peer_log(peer, BLOG_NOTICE, "bound to address number %d", addr_index);
-    
-    *cont = 0;
-}
-
-void peer_connect (struct peer_data *peer, BAddr addr, uint8_t* encryption_key, uint64_t password)
-{
-    // get a fresh link
-    peer_cleanup_connections(peer);
-    if (!peer_init_link(peer)) {
-        peer_log(peer, BLOG_ERROR, "cannot get link");
-        peer_reset(peer);
-        return;
-    }
-    
-    if (options.transport_mode == TRANSPORT_MODE_UDP) {
-        // order DatagramPeerIO to connect
-        if (!DatagramPeerIO_Connect(&peer->pio.udp.pio, addr)) {
-            peer_log(peer, BLOG_NOTICE, "DatagramPeerIO_Connect failed");
-            peer_reset(peer);
-            return;
-        }
-        
-        // set encryption key
-        if (SPPROTO_HAVE_ENCRYPTION(sp_params)) {
-            DatagramPeerIO_SetEncryptionKey(&peer->pio.udp.pio, encryption_key);
-        }
-        
-        // generate and send a send seed
-        if (SPPROTO_HAVE_OTP(sp_params)) {
-            BPending_Set(&peer->pio.udp.job_send_seed);
-        }
-    } else {
-        // order StreamPeerIO to connect
-        if (!StreamPeerIO_Connect(&peer->pio.tcp.pio, addr, password, client_cert, client_key)) {
-            peer_log(peer, BLOG_NOTICE, "StreamPeerIO_Connect failed");
-            peer_reset(peer);
-            return;
-        }
-    }
-}
-
-static int peer_start_msg (struct peer_data *peer, void **data, int type, int len)
-{
-    ASSERT(len >= 0)
-    ASSERT(len <= MSG_MAX_PAYLOAD)
-    ASSERT(!(len > 0) || data)
-    ASSERT(peer->chat_send_msg_len == -1)
-    
-    // make sure we have chat
-    if (!peer->have_chat) {
-        peer_log(peer, BLOG_ERROR, "cannot send message, chat is down");
-        return 0;
-    }
-    
-#ifdef SIMULATE_PEER_OUT_OF_BUFFER
-    uint8_t x;
-    BRandom_randomize(&x, sizeof(x));
-    if (x < SIMULATE_PEER_OUT_OF_BUFFER) {
-        peer_log(peer, BLOG_ERROR, "simulating out of buffer, sending resetpeer");
-        peer_resetpeer(peer);
-        return 0;
-    }
-#endif
-    
-    // obtain buffer location
-    uint8_t *packet;
-    if (!PeerChat_StartMessage(&peer->chat, &packet)) {
-        peer_log(peer, BLOG_ERROR, "cannot send message, out of buffer, sending resetpeer");
-        peer_resetpeer(peer);
-        return 0;
-    }
-    
-    // write fields
-    msgWriter writer;
-    msgWriter_Init(&writer, packet);
-    msgWriter_Addtype(&writer, type);
-    uint8_t *payload_dst = msgWriter_Addpayload(&writer, len);
-    msgWriter_Finish(&writer);
-    
-    // set have message
-    peer->chat_send_msg_len = len;
-    
-    if (data) {
-        *data = payload_dst;
-    }
-    return 1;
-}
-
-static void peer_end_msg (struct peer_data *peer)
-{
-    ASSERT(peer->chat_send_msg_len >= 0)
-    ASSERT(peer->have_chat)
-    
-    // submit packet to buffer
-    PeerChat_EndMessage(&peer->chat, msg_SIZEtype + msg_SIZEpayload(peer->chat_send_msg_len));
-    
-    // set no message
-    peer->chat_send_msg_len = -1;
-}
-
-void peer_send_simple (struct peer_data *peer, int msgid)
-{
-    if (!peer_start_msg(peer, NULL, msgid, 0)) {
-        return;
-    }
-    peer_end_msg(peer);
-}
-
-void peer_send_conectinfo (struct peer_data *peer, int addr_index, int port_adjust, uint8_t *enckey, uint64_t pass)
-{
-    ASSERT(addr_index >= 0)
-    ASSERT(addr_index < num_bind_addrs)
-    ASSERT(bind_addrs[addr_index].num_ext_addrs > 0)
-    
-    // get address
-    struct bind_addr *bind_addr = &bind_addrs[addr_index];
-    
-    // remember encryption key size
-    int key_size = 0; // to remove warning
-    if (options.transport_mode == TRANSPORT_MODE_UDP && SPPROTO_HAVE_ENCRYPTION(sp_params)) {
-        key_size = BEncryption_cipher_key_size(sp_params.encryption_mode);
-    }
-    
-    // calculate message length ..
-    int msg_len = 0;
-    
-    // addresses
-    for (int i = 0; i < bind_addr->num_ext_addrs; i++) {
-        int addrmsg_len =
-            msg_youconnect_addr_SIZEname(strlen(bind_addr->ext_addrs[i].scope)) +
-            msg_youconnect_addr_SIZEaddr(addr_size(bind_addr->ext_addrs[i].addr));
-        msg_len += msg_youconnect_SIZEaddr(addrmsg_len);
-    }
-    
-    // encryption key
-    if (options.transport_mode == TRANSPORT_MODE_UDP && SPPROTO_HAVE_ENCRYPTION(sp_params)) {
-        msg_len += msg_youconnect_SIZEkey(key_size);
-    }
-    
-    // password
-    if (options.transport_mode == TRANSPORT_MODE_TCP) {
-        msg_len += msg_youconnect_SIZEpassword;
-    }
-    
-    // check if it's too big (because of the addresses)
-    if (msg_len > MSG_MAX_PAYLOAD) {
-        BLog(BLOG_ERROR, "cannot send too big youconnect message");
-        return;
-    }
-        
-    // start message
-    uint8_t *msg;
-    if (!peer_start_msg(peer, (void **)&msg, MSGID_YOUCONNECT, msg_len)) {
-        return;
-    }
-        
-    // init writer
-    msg_youconnectWriter writer;
-    msg_youconnectWriter_Init(&writer, msg);
-        
-    // write addresses
-    for (int i = 0; i < bind_addr->num_ext_addrs; i++) {
-        int name_len = strlen(bind_addr->ext_addrs[i].scope);
-        int addr_len = addr_size(bind_addr->ext_addrs[i].addr);
-        
-        // get a pointer for writing the address
-        int addrmsg_len =
-            msg_youconnect_addr_SIZEname(name_len) +
-            msg_youconnect_addr_SIZEaddr(addr_len);
-        uint8_t *addrmsg_dst = msg_youconnectWriter_Addaddr(&writer, addrmsg_len);
-        
-        // init address writer
-        msg_youconnect_addrWriter awriter;
-        msg_youconnect_addrWriter_Init(&awriter, addrmsg_dst);
-        
-        // write scope
-        uint8_t *name_dst = msg_youconnect_addrWriter_Addname(&awriter, name_len);
-        memcpy(name_dst, bind_addr->ext_addrs[i].scope, name_len);
-        
-        // write address with adjusted port
-        BAddr addr = bind_addr->ext_addrs[i].addr;
-        BAddr_SetPort(&addr, hton16(ntoh16(BAddr_GetPort(&addr)) + port_adjust));
-        uint8_t *addr_dst = msg_youconnect_addrWriter_Addaddr(&awriter, addr_len);
-        addr_write(addr_dst, addr);
-        
-        // finish address writer
-        msg_youconnect_addrWriter_Finish(&awriter);
-    }
-    
-    // write encryption key
-    if (options.transport_mode == TRANSPORT_MODE_UDP && SPPROTO_HAVE_ENCRYPTION(sp_params)) {
-        uint8_t *key_dst = msg_youconnectWriter_Addkey(&writer, key_size);
-        memcpy(key_dst, enckey, key_size);
-    }
-    
-    // write password
-    if (options.transport_mode == TRANSPORT_MODE_TCP) {
-        msg_youconnectWriter_Addpassword(&writer, pass);
-    }
-    
-    // finish writer
-    msg_youconnectWriter_Finish(&writer);
-    
-    // end message
-    peer_end_msg(peer);
-}
-
-void peer_send_confirmseed (struct peer_data *peer, uint16_t seed_id)
-{
-    ASSERT(options.transport_mode == TRANSPORT_MODE_UDP)
-    ASSERT(SPPROTO_HAVE_OTP(sp_params))
-    
-    // send confirmation
-    int msg_len = msg_confirmseed_SIZEseed_id;
-    uint8_t *msg;
-    if (!peer_start_msg(peer, (void **)&msg, MSGID_CONFIRMSEED, msg_len)) {
-        return;
-    }
-    msg_confirmseedWriter writer;
-    msg_confirmseedWriter_Init(&writer, msg);
-    msg_confirmseedWriter_Addseed_id(&writer, seed_id);
-    msg_confirmseedWriter_Finish(&writer);
-    peer_end_msg(peer);
-}
-
-void peer_dataproto_handler (struct peer_data *peer, int up)
-{
-    ASSERT(peer->have_link)
-    
-    if (up) {
-        peer_log(peer, BLOG_INFO, "up");
-        
-        // if it can be a relay provided, enable it
-        if ((peer->flags & SCID_NEWCLIENT_FLAG_RELAY_SERVER) && !peer->is_relay) {
-            peer_enable_relay_provider(peer);
-        }
-    } else {
-        peer_log(peer, BLOG_INFO, "down");
-        
-        // if it is a relay provider, disable it
-        if (peer->is_relay) {
-            peer_disable_relay_provider(peer);
-        }
-    }
-}
-
-struct peer_data * find_peer_by_id (peerid_t id)
-{
-    for (LinkedList1Node *node = LinkedList1_GetFirst(&peers); node; node = LinkedList1Node_Next(node)) {
-        struct peer_data *peer = UPPER_OBJECT(node, struct peer_data, list_node);
-        if (peer->id == id) {
-            return peer;
-        }
-    }
-    
-    return NULL;
-}
-
-void device_error_handler (void *unused)
-{
-    BLog(BLOG_ERROR, "device error");
-    
-    terminate();
-}
-
-void device_dpsource_handler (void *unused, const uint8_t *frame, int frame_len)
-{
-    ASSERT(frame_len >= 0)
-    ASSERT(frame_len <= device_mtu)
-    
-    // give frame to decider
-    FrameDecider_AnalyzeAndDecide(&frame_decider, frame, frame_len);
-    
-    // forward frame to peers
-    FrameDeciderPeer *decider_peer = FrameDecider_NextDestination(&frame_decider);
-    while (decider_peer) {
-        FrameDeciderPeer *next = FrameDecider_NextDestination(&frame_decider);
-        struct peer_data *peer = UPPER_OBJECT(decider_peer, struct peer_data, decider_peer);
-        DataProtoFlow_Route(&peer->local_dpflow, !!next);
-        decider_peer = next;
-    }
-}
-
-void assign_relays (void)
-{
-    LinkedList1Node *list_node;
-    while (list_node = LinkedList1_GetFirst(&waiting_relay_peers)) {
-        struct peer_data *peer = UPPER_OBJECT(list_node, struct peer_data, waiting_relay_list_node);
-        ASSERT(peer->waiting_relay)
-        
-        ASSERT(!peer->relaying_peer)
-        ASSERT(!peer->have_link)
-        
-        // get a relay
-        LinkedList1Node *list_node2 = LinkedList1_GetFirst(&relays);
-        if (!list_node2) {
-            BLog(BLOG_NOTICE, "no relays");
-            return;
-        }
-        struct peer_data *relay = UPPER_OBJECT(list_node2, struct peer_data, relay_list_node);
-        ASSERT(relay->is_relay)
-        
-        // no longer waiting for relay
-        peer_unregister_need_relay(peer);
-        
-        // install the relay
-        peer_install_relaying(peer, relay);
-    }
-}
-
-char * address_scope_known (uint8_t *name, int name_len)
-{
-    ASSERT(name_len >= 0)
-    
-    for (int i = 0; i < options.num_scopes; i++) {
-        if (name_len == strlen(options.scopes[i]) && !memcmp(name, options.scopes[i], name_len)) {
-            return options.scopes[i];
-        }
-    }
-    
-    return NULL;
-}
-
-void server_handler_error (void *user)
-{
-    BLog(BLOG_ERROR, "server connection failed, exiting");
-    
-    terminate();
-}
-
-void server_handler_ready (void *user, peerid_t param_my_id, uint32_t ext_ip)
-{
-    ASSERT(!server_ready)
-    
-    // remember our ID
-    my_id = param_my_id;
-    
-    // store server reported addresses
-    for (int i = 0; i < num_bind_addrs; i++) {
-        struct bind_addr *addr = &bind_addrs[i];
-        for (int j = 0; j < addr->num_ext_addrs; j++) {
-            struct ext_addr *eaddr = &addr->ext_addrs[j];
-            if (eaddr->server_reported_port >= 0) {
-                if (ext_ip == 0) {
-                    BLog(BLOG_ERROR, "server did not provide our address");
-                    terminate();
-                    return;
-                }
-                BAddr_InitIPv4(&eaddr->addr, ext_ip, hton16(eaddr->server_reported_port));
-                char str[BADDR_MAX_PRINT_LEN];
-                BAddr_Print(&eaddr->addr, str);
-                BLog(BLOG_INFO, "external address (%d,%d): server reported %s", i, j, str);
-            }
-        }
-    }
-    
-    // give receive device the ID
-    DPReceiveDevice_SetPeerID(&device_output_dprd, my_id);
-    
-    // init server queue
-    if (!PacketPassFairQueue_Init(&server_queue, ServerConnection_GetSendInterface(&server), BReactor_PendingGroup(&ss), 0, 1)) {
-        BLog(BLOG_ERROR, "PacketPassFairQueue_Init failed");
-        terminate();
-        return;
-    }
-    
-    // set server ready
-    server_ready = 1;
-    
-    BLog(BLOG_INFO, "server: ready, my ID is %d", (int)my_id);
-}
-
-void server_handler_newclient (void *user, peerid_t peer_id, int flags, const uint8_t *cert, int cert_len)
-{
-    ASSERT(server_ready)
-    ASSERT(cert_len >= 0)
-    ASSERT(cert_len <= SCID_NEWCLIENT_MAX_CERT_LEN)
-    
-    // check if the peer already exists
-    if (find_peer_by_id(peer_id)) {
-        BLog(BLOG_WARNING, "server: newclient: peer already known");
-        return;
-    }
-    
-    // make sure it's not the same ID as us
-    if (peer_id == my_id) {
-        BLog(BLOG_WARNING, "server: newclient: peer has our ID");
-        return;
-    }
-    
-    // check if there is spece for the peer
-    if (num_peers >= options.max_peers) {
-        BLog(BLOG_WARNING, "server: newclient: no space for new peer (maximum number reached)");
-        return;
-    }
-    
-    if (!options.ssl && cert_len > 0) {
-        BLog(BLOG_WARNING, "server: newclient: certificate supplied, but not using TLS");
-        return;
-    }
-    
-    peer_add(peer_id, flags, cert, cert_len);
-}
-
-void server_handler_endclient (void *user, peerid_t peer_id)
-{
-    ASSERT(server_ready)
-    
-    // find peer
-    struct peer_data *peer = find_peer_by_id(peer_id);
-    if (!peer) {
-        BLog(BLOG_WARNING, "server: endclient: peer %d not known", (int)peer_id);
-        return;
-    }
-    
-    // remove peer
-    peer_remove(peer, 0);
-}
-
-void server_handler_message (void *user, peerid_t peer_id, uint8_t *data, int data_len)
-{
-    ASSERT(server_ready)
-    ASSERT(data_len >= 0)
-    ASSERT(data_len <= SC_MAX_MSGLEN)
-    
-    // find peer
-    struct peer_data *peer = find_peer_by_id(peer_id);
-    if (!peer) {
-        BLog(BLOG_WARNING, "server: message: peer not known");
-        return;
-    }
-    
-    // make sure we have chat
-    if (!peer->have_chat) {
-        peer_log(peer, BLOG_ERROR, "cannot process message, chat is down");
-        return;
-    }
-    
-    // pass message to chat
-    PeerChat_InputReceived(&peer->chat, data, data_len);
-}
-
-void peer_job_send_seed (struct peer_data *peer)
-{
-    ASSERT(options.transport_mode == TRANSPORT_MODE_UDP)
-    ASSERT(SPPROTO_HAVE_OTP(sp_params))
-    ASSERT(peer->have_link)
-    ASSERT(!peer->pio.udp.sendseed_sent)
-    
-    peer_log(peer, BLOG_DEBUG, "sending OTP send seed");
-    
-    int key_len = BEncryption_cipher_key_size(sp_params.otp_mode);
-    int iv_len = BEncryption_cipher_block_size(sp_params.otp_mode);
-    
-    // generate seed
-    peer->pio.udp.sendseed_sent_id = peer->pio.udp.sendseed_nextid;
-    BRandom_randomize(peer->pio.udp.sendseed_sent_key, key_len);
-    BRandom_randomize(peer->pio.udp.sendseed_sent_iv, iv_len);
-    
-    // set as sent, increment next seed ID
-    peer->pio.udp.sendseed_sent = 1;
-    peer->pio.udp.sendseed_nextid++;
-    
-    // send seed to the peer
-    int msg_len = msg_seed_SIZEseed_id + msg_seed_SIZEkey(key_len) + msg_seed_SIZEiv(iv_len);
-    if (msg_len > MSG_MAX_PAYLOAD) {
-        peer_log(peer, BLOG_ERROR, "OTP send seed message too big");
-        return;
-    }
-    uint8_t *msg;
-    if (!peer_start_msg(peer, (void **)&msg, MSGID_SEED, msg_len)) {
-        return;
-    }
-    msg_seedWriter writer;
-    msg_seedWriter_Init(&writer, msg);
-    msg_seedWriter_Addseed_id(&writer, peer->pio.udp.sendseed_sent_id);
-    uint8_t *key_dst = msg_seedWriter_Addkey(&writer, key_len);
-    memcpy(key_dst, peer->pio.udp.sendseed_sent_key, key_len);
-    uint8_t *iv_dst = msg_seedWriter_Addiv(&writer, iv_len);
-    memcpy(iv_dst, peer->pio.udp.sendseed_sent_iv, iv_len);
-    msg_seedWriter_Finish(&writer);
-    peer_end_msg(peer);
-}
-
-void peer_job_init (struct peer_data *peer)
-{
-    // start setup process
-    if (peer_am_master(peer)) {
-        peer_start_binding(peer);
-    }
-}
-
-struct server_flow * server_flow_init (void)
-{
-    ASSERT(server_ready)
-    
-    // allocate structure
-    struct server_flow *flow = (struct server_flow *)malloc(sizeof(*flow));
-    if (!flow) {
-        BLog(BLOG_ERROR, "malloc failed");
-        goto fail0;
-    }
-    
-    // init queue flow
-    PacketPassFairQueueFlow_Init(&flow->qflow, &server_queue);
-    
-    // init connector
-    PacketRecvConnector_Init(&flow->connector, sizeof(struct packetproto_header) + SC_MAX_ENC, BReactor_PendingGroup(&ss));
-    
-    // init encoder buffer
-    if (!SinglePacketBuffer_Init(&flow->encoder_buffer, PacketRecvConnector_GetOutput(&flow->connector), PacketPassFairQueueFlow_GetInput(&flow->qflow), BReactor_PendingGroup(&ss))) {
-        BLog(BLOG_ERROR, "SinglePacketBuffer_Init failed");
-        goto fail1;
-    }
-    
-    // set not connected
-    flow->connected = 0;
-    
-    return flow;
-    
-fail1:
-    PacketRecvConnector_Free(&flow->connector);
-    PacketPassFairQueueFlow_Free(&flow->qflow);
-    free(flow);
-fail0:
-    return NULL;
-}
-
-void server_flow_free (struct server_flow *flow)
-{
-    PacketPassFairQueueFlow_AssertFree(&flow->qflow);
-    ASSERT(!flow->connected)
-    
-    // remove dying flow reference
-    if (flow == dying_server_flow) {
-        dying_server_flow = NULL;
-    }
-    
-    // free encoder buffer
-    SinglePacketBuffer_Free(&flow->encoder_buffer);
-    
-    // free connector
-    PacketRecvConnector_Free(&flow->connector);
-    
-    // free queue flow
-    PacketPassFairQueueFlow_Free(&flow->qflow);
-    
-    // free structure
-    free(flow);
-}
-
-void server_flow_die (struct server_flow *flow)
-{
-    ASSERT(PacketPassFairQueueFlow_IsBusy(&flow->qflow))
-    ASSERT(!flow->connected)
-    ASSERT(!dying_server_flow)
-    
-    // request notification when flow is done
-    PacketPassFairQueueFlow_SetBusyHandler(&flow->qflow, (PacketPassFairQueue_handler_busy)server_flow_qflow_handler_busy, flow);
-    
-    // set dying flow
-    dying_server_flow = flow;
-}
-
-void server_flow_qflow_handler_busy (struct server_flow *flow)
-{
-    ASSERT(flow == dying_server_flow)
-    ASSERT(!flow->connected)
-    PacketPassFairQueueFlow_AssertFree(&flow->qflow);
-    
-    // finally free flow
-    server_flow_free(flow);
-}
-
-void server_flow_connect (struct server_flow *flow, PacketRecvInterface *input)
-{
-    ASSERT(!flow->connected)
-    ASSERT(flow != dying_server_flow)
-    
-    // connect input
-    PacketRecvConnector_ConnectInput(&flow->connector, input);
-    
-    // set connected
-    flow->connected = 1;
-}
-
-void server_flow_disconnect (struct server_flow *flow)
-{
-    ASSERT(flow->connected)
-    ASSERT(flow != dying_server_flow)
-    
-    // disconnect input
-    PacketRecvConnector_DisconnectInput(&flow->connector);
-    
-    // set not connected
-    flow->connected = 0;
-}
diff --git a/external/badvpn_dns/client/client.h b/external/badvpn_dns/client/client.h
deleted file mode 100644
index 595ed59..0000000
--- a/external/badvpn_dns/client/client.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/**
- * @file client.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-
-#include <protocol/scproto.h>
-#include <structure/LinkedList1.h>
-#include <flow/PacketPassFairQueue.h>
-#include <flow/SinglePacketBuffer.h>
-#include <flow/PacketRecvConnector.h>
-#include <client/DatagramPeerIO.h>
-#include <client/StreamPeerIO.h>
-#include <client/DataProto.h>
-#include <client/DPReceive.h>
-#include <client/FrameDecider.h>
-#include <client/PeerChat.h>
-#include <client/SinglePacketSource.h>
-
-// NOTE: all time values are in milliseconds
-
-// name of the program
-#define PROGRAM_NAME "client"
-
-// server output buffer size
-#define SERVER_BUFFER_MIN_PACKETS 200
-
-// maximum UDP payload size
-#define CLIENT_UDP_MTU 1472
-
-// maximum number of pending TCP PasswordListener clients
-#define TCP_MAX_PASSWORD_LISTENER_CLIENTS 50
-
-// maximum number of peers
-#define DEFAULT_MAX_PEERS 256
-// maximum number of peer's MAC addresses to remember
-#define PEER_DEFAULT_MAX_MACS 16
-// maximum number of multicast addresses per peer
-#define PEER_DEFAULT_MAX_GROUPS 16
-// how long we wait for a packet to reach full size before sending it (see FragmentProtoDisassembler latency argument)
-#define PEER_DEFAULT_UDP_FRAGMENTATION_LATENCY 0
-// value related to how much out-of-order input we tolerate (see FragmentProtoAssembler num_frames argument)
-#define PEER_UDP_ASSEMBLER_NUM_FRAMES 4
-// socket send buffer (SO_SNDBUF) for peer TCP connections, <=0 to not set
-#define PEER_DEFAULT_TCP_SOCKET_SNDBUF 1048576
-// keep-alive packet interval for p2p communication
-#define PEER_KEEPALIVE_INTERVAL 10000
-// keep-alive receive timer for p2p communication (after how long to consider the link down)
-#define PEER_KEEPALIVE_RECEIVE_TIMER 22000
-// size of frame send buffer, in number of frames
-#define PEER_DEFAULT_SEND_BUFFER_SIZE 32
-// size of frame send buffer for relayed packets, in number of frames
-#define PEER_DEFAULT_SEND_BUFFER_RELAY_SIZE 32
-// time after an unused relay flow is freed (-1 for never)
-#define PEER_RELAY_FLOW_INACTIVITY_TIME 10000
-// retry time
-#define PEER_RETRY_TIME 5000
-
-// for how long a peer can send no Membership Reports for a group
-// before the peer and group are disassociated
-#define DEFAULT_IGMP_GROUP_MEMBERSHIP_INTERVAL 260000
-// how long to wait for joins after a Group Specific query has been
-// forwarded to a peer before assuming there are no listeners at the peer
-#define DEFAULT_IGMP_LAST_MEMBER_QUERY_TIME 2000
-
-// maximum bind addresses
-#define MAX_BIND_ADDRS 8
-// maximum external addresses per bind address
-#define MAX_EXT_ADDRS 8
-// maximum scopes
-#define MAX_SCOPES 8
-
-//#define SIMULATE_PEER_OUT_OF_BUFFER 70
-
-struct server_flow {
-    PacketPassFairQueueFlow qflow;
-    SinglePacketBuffer encoder_buffer;
-    PacketRecvConnector connector;
-    int connected;
-};
-
-struct peer_data {
-    // peer identifier
-    peerid_t id;
-    
-    // flags provided by the server
-    int flags;
-    
-    // certificate reported by the server, defined only if using SSL
-    uint8_t cert[SCID_NEWCLIENT_MAX_CERT_LEN];
-    int cert_len;
-    char *common_name;
-    
-    // init job
-    BPending job_init;
-    
-    // server flow
-    struct server_flow *server_flow;
-    
-    // chat
-    int have_chat;
-    PeerChat chat;
-    int chat_send_msg_len;
-    
-    // resetpeer source (when chat fails)
-    int have_resetpeer;
-    uint8_t resetpeer_packet[sizeof(struct packetproto_header) + sizeof(struct sc_header) + sizeof(struct sc_client_resetpeer)];
-    SinglePacketSource resetpeer_source;
-    
-    // local flow
-    DataProtoFlow local_dpflow;
-    
-    // frame decider peer
-    FrameDeciderPeer decider_peer;
-    
-    // receive peer
-    DPReceivePeer receive_peer;
-    
-    // flag if link objects are initialized
-    int have_link;
-    
-    // receive receiver
-    DPReceiveReceiver receive_receiver;
-    
-    // transport-specific link objects
-    union {
-        struct {
-            DatagramPeerIO pio;
-            uint16_t sendseed_nextid;
-            int sendseed_sent;
-            uint16_t sendseed_sent_id;
-            uint8_t sendseed_sent_key[BENCRYPTION_MAX_KEY_SIZE];
-            uint8_t sendseed_sent_iv[BENCRYPTION_MAX_BLOCK_SIZE];
-            uint16_t pending_recvseed_id;
-            BPending job_send_seed;
-        } udp;
-        struct {
-            StreamPeerIO pio;
-        } tcp;
-    } pio;
-    
-    // link sending
-    DataProtoSink send_dp;
-    
-    // relaying objects
-    struct peer_data *relaying_peer; // peer through which we are relaying, or NULL
-    LinkedList1Node relaying_list_node; // node in relay peer's relay_users
-    
-    // waiting for relay data
-    int waiting_relay;
-    LinkedList1Node waiting_relay_list_node;
-    
-    // retry timer
-    BTimer reset_timer;
-    
-    // relay server specific
-    int is_relay;
-    LinkedList1Node relay_list_node;
-    LinkedList1 relay_users;
-    
-    // binding state
-    int binding;
-    int binding_addrpos;
-    
-    // peers linked list node
-    LinkedList1Node list_node;
-};
diff --git a/external/badvpn_dns/cmake/modules/COPYING-CMAKE-SCRIPTS b/external/badvpn_dns/cmake/modules/COPYING-CMAKE-SCRIPTS
deleted file mode 100644
index 4b41776..0000000
--- a/external/badvpn_dns/cmake/modules/COPYING-CMAKE-SCRIPTS
+++ /dev/null
@@ -1,22 +0,0 @@
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-
-1. Redistributions of source code must retain the copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. The name of the author may not be used to endorse or promote products 
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/external/badvpn_dns/cmake/modules/FindGLIB2.cmake b/external/badvpn_dns/cmake/modules/FindGLIB2.cmake
deleted file mode 100644
index 09fd98d..0000000
--- a/external/badvpn_dns/cmake/modules/FindGLIB2.cmake
+++ /dev/null
@@ -1,52 +0,0 @@
-# - Try to find the GLIB2 libraries
-# Once done this will define
-#
-#  GLIB2_FOUND - system has glib2
-#  GLIB2_INCLUDE_DIR - the glib2 include directory
-#  GLIB2_LIBRARIES - glib2 library
-
-# Copyright (c) 2008 Laurent Montel, <montel at kde.org>
-#
-# Redistribution and use is allowed according to the terms of the BSD license.
-# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
-
-
-if(GLIB2_INCLUDE_DIR AND GLIB2_LIBRARIES)
-    # Already in cache, be silent
-    set(GLIB2_FIND_QUIETLY TRUE)
-endif(GLIB2_INCLUDE_DIR AND GLIB2_LIBRARIES)
-
-find_package(PkgConfig)
-pkg_check_modules(PC_LibGLIB2 QUIET glib-2.0)
-
-find_path(GLIB2_MAIN_INCLUDE_DIR
-          NAMES glib.h
-          HINTS ${PC_LibGLIB2_INCLUDEDIR}
-          PATH_SUFFIXES glib-2.0)
-
-find_library(GLIB2_LIBRARY 
-             NAMES glib-2.0 
-             HINTS ${PC_LibGLIB2_LIBDIR}
-)
-
-set(GLIB2_LIBRARIES ${GLIB2_LIBRARY})
-
-# search the glibconfig.h include dir under the same root where the library is found
-get_filename_component(glib2LibDir "${GLIB2_LIBRARIES}" PATH)
-
-find_path(GLIB2_INTERNAL_INCLUDE_DIR glibconfig.h
-          PATH_SUFFIXES glib-2.0/include
-          HINTS ${PC_LibGLIB2_INCLUDEDIR} "${glib2LibDir}" ${CMAKE_SYSTEM_LIBRARY_PATH})
-
-set(GLIB2_INCLUDE_DIR "${GLIB2_MAIN_INCLUDE_DIR}")
-
-# not sure if this include dir is optional or required
-# for now it is optional
-if(GLIB2_INTERNAL_INCLUDE_DIR)
-  set(GLIB2_INCLUDE_DIR ${GLIB2_INCLUDE_DIR} "${GLIB2_INTERNAL_INCLUDE_DIR}")
-endif(GLIB2_INTERNAL_INCLUDE_DIR)
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(GLIB2  DEFAULT_MSG  GLIB2_LIBRARIES GLIB2_MAIN_INCLUDE_DIR)
-
-mark_as_advanced(GLIB2_INCLUDE_DIR GLIB2_LIBRARIES)
diff --git a/external/badvpn_dns/cmake/modules/FindLibraryWithDebug.cmake b/external/badvpn_dns/cmake/modules/FindLibraryWithDebug.cmake
deleted file mode 100644
index 58cd730..0000000
--- a/external/badvpn_dns/cmake/modules/FindLibraryWithDebug.cmake
+++ /dev/null
@@ -1,113 +0,0 @@
-#
-#  FIND_LIBRARY_WITH_DEBUG
-#  -> enhanced FIND_LIBRARY to allow the search for an
-#     optional debug library with a WIN32_DEBUG_POSTFIX similar
-#     to CMAKE_DEBUG_POSTFIX when creating a shared lib
-#     it has to be the second and third argument
-
-# Copyright (c) 2007, Christian Ehrlicher, <ch.ehrlicher at gmx.de>
-# Redistribution and use is allowed according to the terms of the BSD license.
-# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
-
-MACRO(FIND_LIBRARY_WITH_DEBUG var_name win32_dbg_postfix_name dgb_postfix libname)
-
-  IF(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX")
-
-     # no WIN32_DEBUG_POSTFIX -> simply pass all arguments to FIND_LIBRARY
-     FIND_LIBRARY(${var_name}
-                  ${win32_dbg_postfix_name}
-                  ${dgb_postfix}
-                  ${libname}
-                  ${ARGN}
-     )
-
-  ELSE(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX")
-
-    IF(NOT WIN32)
-      # on non-win32 we don't need to take care about WIN32_DEBUG_POSTFIX
-
-      FIND_LIBRARY(${var_name} ${libname} ${ARGN})
-
-    ELSE(NOT WIN32)
-
-      # 1. get all possible libnames
-      SET(args ${ARGN})
-      SET(newargs "")
-      SET(libnames_release "")
-      SET(libnames_debug "")
-
-      LIST(LENGTH args listCount)
-
-      IF("${libname}" STREQUAL "NAMES")
-        SET(append_rest 0)
-        LIST(APPEND args " ")
-
-        FOREACH(i RANGE ${listCount})
-          LIST(GET args ${i} val)
-
-          IF(append_rest)
-            LIST(APPEND newargs ${val})
-          ELSE(append_rest)
-            IF("${val}" STREQUAL "PATHS")
-              LIST(APPEND newargs ${val})
-              SET(append_rest 1)
-            ELSE("${val}" STREQUAL "PATHS")
-              LIST(APPEND libnames_release "${val}")
-              LIST(APPEND libnames_debug   "${val}${dgb_postfix}")
-            ENDIF("${val}" STREQUAL "PATHS")
-          ENDIF(append_rest)
-
-        ENDFOREACH(i)
-
-      ELSE("${libname}" STREQUAL "NAMES")
-
-        # just one name
-        LIST(APPEND libnames_release "${libname}")
-        LIST(APPEND libnames_debug   "${libname}${dgb_postfix}")
-
-        SET(newargs ${args})
-
-      ENDIF("${libname}" STREQUAL "NAMES")
-
-      # search the release lib
-      FIND_LIBRARY(${var_name}_RELEASE
-                   NAMES ${libnames_release}
-                   ${newargs}
-      )
-
-      # search the debug lib
-      FIND_LIBRARY(${var_name}_DEBUG
-                   NAMES ${libnames_debug}
-                   ${newargs}
-      )
-
-      IF(${var_name}_RELEASE AND ${var_name}_DEBUG)
-
-        # both libs found
-        SET(${var_name} optimized ${${var_name}_RELEASE}
-                        debug     ${${var_name}_DEBUG})
-
-      ELSE(${var_name}_RELEASE AND ${var_name}_DEBUG)
-
-        IF(${var_name}_RELEASE)
-
-          # only release found
-          SET(${var_name} ${${var_name}_RELEASE})
-
-        ELSE(${var_name}_RELEASE)
-
-          # only debug (or nothing) found
-          SET(${var_name} ${${var_name}_DEBUG})
-
-        ENDIF(${var_name}_RELEASE)
-       
-      ENDIF(${var_name}_RELEASE AND ${var_name}_DEBUG)
-
-      MARK_AS_ADVANCED(${var_name}_RELEASE)
-      MARK_AS_ADVANCED(${var_name}_DEBUG)
-
-    ENDIF(NOT WIN32)
-
-  ENDIF(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX")
-
-ENDMACRO(FIND_LIBRARY_WITH_DEBUG)
diff --git a/external/badvpn_dns/cmake/modules/FindNSPR.cmake b/external/badvpn_dns/cmake/modules/FindNSPR.cmake
deleted file mode 100644
index 6e8fed9..0000000
--- a/external/badvpn_dns/cmake/modules/FindNSPR.cmake
+++ /dev/null
@@ -1,57 +0,0 @@
-# - Try to find the NSPR library
-# Once done this will define
-#
-#  NSPR_FOUND - system has the NSPR library
-#  NSPR_INCLUDE_DIRS - Include paths needed
-#  NSPR_LIBRARY_DIRS - Linker paths needed
-#  NSPR_LIBRARIES - Libraries needed
-
-# Copyright (c) 2010, Ambroz Bizjak, <ambrop7 at gmail.com>
-#
-# Redistribution and use is allowed according to the terms of the BSD license.
-# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
-
-include(FindLibraryWithDebug)
-
-if (NSPR_LIBRARIES)
-   set(NSPR_FIND_QUIETLY TRUE)
-endif ()
-
-set(NSPR_FOUND FALSE)
-
-if (WIN32)
-    find_path(NSPR_FIND_INCLUDE_DIR prerror.h)
-
-    FIND_LIBRARY_WITH_DEBUG(NSPR_FIND_LIBRARIES_PLDS WIN32_DEBUG_POSTFIX d NAMES plds4 libplds4)
-    FIND_LIBRARY_WITH_DEBUG(NSPR_FIND_LIBRARIES_PLC WIN32_DEBUG_POSTFIX d NAMES plc4 libplc4)
-    FIND_LIBRARY_WITH_DEBUG(NSPR_FIND_LIBRARIES_NSPR WIN32_DEBUG_POSTFIX d NAMES nspr4 libnspr4)
-
-    if (NSPR_FIND_INCLUDE_DIR AND NSPR_FIND_LIBRARIES_PLDS AND NSPR_FIND_LIBRARIES_PLC AND NSPR_FIND_LIBRARIES_NSPR)
-        set(NSPR_FOUND TRUE)
-        set(NSPR_INCLUDE_DIRS "${NSPR_FIND_INCLUDE_DIR}" CACHE STRING "NSPR include dirs")
-        set(NSPR_LIBRARY_DIRS "" CACHE STRING "NSPR library dirs")
-        set(NSPR_LIBRARIES "${NSPR_FIND_LIBRARIES_PLDS};${NSPR_FIND_LIBRARIES_PLC};${NSPR_FIND_LIBRARIES_NSPR}" CACHE STRING "NSPR libraries")
-    endif ()
-else ()
-    find_package(PkgConfig REQUIRED)
-    pkg_check_modules(NSPR_PC nspr)
-
-    if (NSPR_PC_FOUND)
-        set(NSPR_FOUND TRUE)
-        set(NSPR_INCLUDE_DIRS "${NSPR_PC_INCLUDE_DIRS}" CACHE STRING "NSPR include dirs")
-        set(NSPR_LIBRARY_DIRS "${NSPR_PC_LIBRARY_DIRS}" CACHE STRING "NSPR library dirs")
-        set(NSPR_LIBRARIES "${NSPR_PC_LIBRARIES}" CACHE STRING "NSPR libraries")
-    endif ()
-endif ()
-
-if (NSPR_FOUND)
-    if (NOT NSPR_FIND_QUIETLY)
-        MESSAGE(STATUS "Found NSPR: ${NSPR_INCLUDE_DIRS} ${NSPR_LIBRARY_DIRS} ${NSPR_LIBRARIES}")
-    endif ()
-else ()
-    if (NSPR_FIND_REQUIRED)
-        message(FATAL_ERROR "Could NOT find NSPR")
-    endif ()
-endif ()
-
-mark_as_advanced(NSPR_INCLUDE_DIRS NSPR_LIBRARY_DIRS NSPR_LIBRARIES)
diff --git a/external/badvpn_dns/cmake/modules/FindNSS.cmake b/external/badvpn_dns/cmake/modules/FindNSS.cmake
deleted file mode 100644
index 17fd45a..0000000
--- a/external/badvpn_dns/cmake/modules/FindNSS.cmake
+++ /dev/null
@@ -1,57 +0,0 @@
-# - Try to find the NSS library
-# Once done this will define
-#
-#  NSS_FOUND - system has the NSS library
-#  NSS_INCLUDE_DIRS - Include paths needed
-#  NSS_LIBRARY_DIRS - Linker paths needed
-#  NSS_LIBRARIES - Libraries needed
-
-# Copyright (c) 2010, Ambroz Bizjak, <ambrop7 at gmail.com>
-#
-# Redistribution and use is allowed according to the terms of the BSD license.
-# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
-
-include(FindLibraryWithDebug)
-
-if (NSS_LIBRARIES)
-   set(NSS_FIND_QUIETLY TRUE)
-endif ()
-
-set(NSS_FOUND FALSE)
-
-if (WIN32)
-    find_path(NSS_FIND_INCLUDE_DIR nss.h)
-
-    FIND_LIBRARY_WITH_DEBUG(NSS_FIND_LIBRARIES_SSL WIN32_DEBUG_POSTFIX d NAMES ssl3)
-    FIND_LIBRARY_WITH_DEBUG(NSS_FIND_LIBRARIES_SMIME WIN32_DEBUG_POSTFIX d NAMES smime3)
-    FIND_LIBRARY_WITH_DEBUG(NSS_FIND_LIBRARIES_NSS WIN32_DEBUG_POSTFIX d NAMES nss3)
-
-    if (NSS_FIND_INCLUDE_DIR AND NSS_FIND_LIBRARIES_SSL AND NSS_FIND_LIBRARIES_SMIME AND NSS_FIND_LIBRARIES_NSS)
-        set(NSS_FOUND TRUE)
-        set(NSS_INCLUDE_DIRS "${NSS_FIND_INCLUDE_DIR}" CACHE STRING "NSS include dirs")
-        set(NSS_LIBRARY_DIRS "" CACHE STRING "NSS library dirs")
-        set(NSS_LIBRARIES "${NSS_FIND_LIBRARIES_SSL};${NSS_FIND_LIBRARIES_SMIME};${NSS_FIND_LIBRARIES_NSS}" CACHE STRING "NSS libraries")
-    endif ()
-else ()
-    find_package(PkgConfig REQUIRED)
-    pkg_check_modules(NSS_PC nss)
-
-    if (NSS_PC_FOUND)
-        set(NSS_FOUND TRUE)
-        set(NSS_INCLUDE_DIRS "${NSS_PC_INCLUDE_DIRS}" CACHE STRING "NSS include dirs")
-        set(NSS_LIBRARY_DIRS "${NSS_PC_LIBRARY_DIRS}" CACHE STRING "NSS library dirs")
-        set(NSS_LIBRARIES "${NSS_PC_LIBRARIES}" CACHE STRING "NSS libraries")
-    endif ()
-endif ()
-
-if (NSS_FOUND)
-    if (NOT NSS_FIND_QUIETLY)
-        MESSAGE(STATUS "Found NSS: ${NSS_INCLUDE_DIRS} ${NSS_LIBRARY_DIRS} ${NSS_LIBRARIES}")
-    endif ()
-else ()
-    if (NSS_FIND_REQUIRED)
-        message(FATAL_ERROR "Could NOT find NSS")
-    endif ()
-endif ()
-
-mark_as_advanced(NSS_INCLUDE_DIRS NSS_LIBRARY_DIRS NSS_LIBRARIES)
diff --git a/external/badvpn_dns/cmake/modules/FindOpenSSL.cmake b/external/badvpn_dns/cmake/modules/FindOpenSSL.cmake
deleted file mode 100644
index 4434e95..0000000
--- a/external/badvpn_dns/cmake/modules/FindOpenSSL.cmake
+++ /dev/null
@@ -1,72 +0,0 @@
-# - Try to find the OpenSSL library
-# Once done this will define
-#
-#  OpenSSL_FOUND - system has the OpenSSL library
-#  OpenSSL_INCLUDE_DIRS - Include paths needed
-#  OpenSSL_LIBRARY_DIRS - Linker paths needed
-#  OpenSSL_LIBRARIES - Libraries needed
-
-# Copyright (c) 2010, Ambroz Bizjak, <ambrop7 at gmail.com>
-#
-# Redistribution and use is allowed according to the terms of the BSD license.
-# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
-
-include(FindLibraryWithDebug)
-
-if (OpenSSL_LIBRARIES)
-   set(OpenSSL_FIND_QUIETLY TRUE)
-endif ()
-
-set(OpenSSL_FOUND FALSE)
-
-if (WIN32)
-    find_path(OpenSSL_FIND_INCLUDE_DIR openssl/ssl.h)
-
-    if (OpenSSL_FIND_INCLUDE_DIR)
-        # look for libraries built with GCC
-        find_library(OpenSSL_FIND_LIBRARIES_SSL NAMES ssl)
-        find_library(OpenSSL_FIND_LIBRARIES_CRYPTO NAMES crypto)
-
-        if (OpenSSL_FIND_LIBRARIES_SSL AND OpenSSL_FIND_LIBRARIES_CRYPTO)
-            set(OpenSSL_FOUND TRUE)
-            set(OpenSSL_LIBRARY_DIRS "" CACHE STRING "OpenSSL library dirs")
-            set(OpenSSL_LIBRARIES "${OpenSSL_FIND_LIBRARIES_SSL};${OpenSSL_FIND_LIBRARIES_CRYPTO}" CACHE STRING "OpenSSL libraries")
-        else ()
-            # look for libraries built with MSVC
-            FIND_LIBRARY_WITH_DEBUG(OpenSSL_FIND_LIBRARIES_SSL WIN32_DEBUG_POSTFIX d NAMES ssl ssleay ssleay32 libssleay32 ssleay32MD)
-            FIND_LIBRARY_WITH_DEBUG(OpenSSL_FIND_LIBRARIES_EAY WIN32_DEBUG_POSTFIX d NAMES eay libeay libeay32 libeay32MD)
-
-            if (OpenSSL_FIND_LIBRARIES_SSL AND OpenSSL_FIND_LIBRARIES_EAY)
-                set(OpenSSL_FOUND TRUE)
-                set(OpenSSL_LIBRARY_DIRS "" CACHE STRING "OpenSSL library dirs")
-                set(OpenSSL_LIBRARIES "${OpenSSL_FIND_LIBRARIES_SSL};${OpenSSL_FIND_LIBRARIES_EAY}" CACHE STRING "OpenSSL libraries")
-            endif ()
-        endif ()
-
-        if (OpenSSL_FOUND)
-            set(OpenSSL_INCLUDE_DIRS "${OpenSSL_FIND_INCLUDE_DIR}" CACHE STRING "OpenSSL include dirs")
-        endif ()
-    endif ()
-else ()
-    find_package(PkgConfig REQUIRED)
-    pkg_check_modules(OpenSSL_PC openssl)
-
-    if (OpenSSL_PC_FOUND)
-        set(OpenSSL_FOUND TRUE)
-        set(OpenSSL_INCLUDE_DIRS "${OpenSSL_PC_INCLUDE_DIRS}" CACHE STRING "OpenSSL include dirs")
-        set(OpenSSL_LIBRARY_DIRS "${OpenSSL_PC_LIBRARY_DIRS}" CACHE STRING "OpenSSL library dirs")
-        set(OpenSSL_LIBRARIES "${OpenSSL_PC_LIBRARIES}" CACHE STRING "OpenSSL libraries")
-    endif ()
-endif ()
-
-if (OpenSSL_FOUND)
-    if (NOT OpenSSL_FIND_QUIETLY)
-        MESSAGE(STATUS "Found OpenSSL: ${OpenSSL_INCLUDE_DIRS} ${OpenSSL_LIBRARY_DIRS} ${OpenSSL_LIBRARIES}")
-    endif ()
-else ()
-    if (OpenSSL_FIND_REQUIRED)
-        message(FATAL_ERROR "Could NOT find OpenSSL")
-    endif ()
-endif ()
-
-mark_as_advanced(OpenSSL_INCLUDE_DIRS OpenSSL_LIBRARY_DIRS OpenSSL_LIBRARIES)
diff --git a/external/badvpn_dns/compile-tun2sock.sh b/external/badvpn_dns/compile-tun2sock.sh
deleted file mode 100755
index fbc2388..0000000
--- a/external/badvpn_dns/compile-tun2sock.sh
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/bin/bash
-#
-# Compiles tun2socks for Linux.
-# Intended as a convenience if you don't want to deal with CMake.
-
-# Input environment vars:
-#   SRCDIR - BadVPN source code
-#   CC - compiler
-#   CFLAGS - compiler compile flags
-#   LDFLAGS - compiler link flags
-#   ENDIAN - "little" or "big"
-#   KERNEL - "2.6" or "2.4", default "2.6"
-#
-# Puts object files and the executable in the working directory.
-#
-
-if [[ -z $SRCDIR ]] || [[ ! -e $SRCDIR/CMakeLists.txt ]]; then
-    echo "SRCDIR is wrong"
-    exit 1
-fi
-
-if ! "${CC}" --version &>/dev/null; then
-    echo "CC is wrong"
-    exit 1
-fi
-
-if [[ $ENDIAN != "little" ]] && [[ $ENDIAN != "big" ]]; then
-    echo "ENDIAN is wrong"
-    exit 1
-fi
-
-if [[ -z $KERNEL ]]; then
-    KERNEL="2.6"
-elif [[ $KERNEL != "2.6" ]] && [[ $KERNEL != "2.4" ]]; then
-    echo "KERNEL is wrong"
-    exit 1
-fi
-
-CFLAGS="${CFLAGS} -std=gnu99"
-INCLUDES=( "-I${SRCDIR}" "-I${SRCDIR}/lwip/src/include/ipv4" "-I${SRCDIR}/lwip/src/include/ipv6" "-I${SRCDIR}/lwip/src/include" "-I${SRCDIR}/lwip/custom" )
-DEFS=( -DBADVPN_THREAD_SAFE=0 -DBADVPN_LINUX -DBADVPN_BREACTOR_BADVPN -D_GNU_SOURCE )
-
-[[ $KERNEL = "2.4" ]] && DEFS=( "${DEFS[@]}" -DBADVPN_USE_SELFPIPE -DBADVPN_USE_POLL ) || DEFS=( "${DEFS[@]}" -DBADVPN_USE_SIGNALFD -DBADVPN_USE_EPOLL )
-
-[[ $ENDIAN = "little" ]] && DEFS=( "${DEFS[@]}" -DBADVPN_LITTLE_ENDIAN ) || DEFS=( "${DEFS[@]}" -DBADVPN_BIG_ENDIAN )
-    
-SOURCES="
-base/BLog_syslog.c
-system/BReactor_badvpn.c
-system/BSignal.c
-system/BConnection_unix.c
-system/BTime.c
-system/BUnixSignal.c
-system/BNetwork.c
-flow/StreamRecvInterface.c
-flow/PacketRecvInterface.c
-flow/PacketPassInterface.c
-flow/StreamPassInterface.c
-flow/SinglePacketBuffer.c
-flow/BufferWriter.c
-flow/PacketBuffer.c
-flow/PacketStreamSender.c
-flow/PacketPassConnector.c
-flow/PacketProtoFlow.c
-flow/PacketPassFairQueue.c
-flow/PacketProtoEncoder.c
-flow/PacketProtoDecoder.c
-socksclient/BSocksClient.c
-tuntap/BTap.c
-lwip/src/core/timers.c
-lwip/src/core/udp.c
-lwip/src/core/memp.c
-lwip/src/core/init.c
-lwip/src/core/pbuf.c
-lwip/src/core/tcp.c
-lwip/src/core/tcp_out.c
-lwip/src/core/netif.c
-lwip/src/core/def.c
-lwip/src/core/mem.c
-lwip/src/core/tcp_in.c
-lwip/src/core/stats.c
-lwip/src/core/inet_chksum.c
-lwip/src/core/ipv4/icmp.c
-lwip/src/core/ipv4/ip4.c
-lwip/src/core/ipv4/ip4_addr.c
-lwip/src/core/ipv4/ip_frag.c
-lwip/src/core/ipv6/ip6.c
-lwip/src/core/ipv6/nd6.c
-lwip/src/core/ipv6/icmp6.c
-lwip/src/core/ipv6/ip6_addr.c
-lwip/src/core/ipv6/ip6_frag.c
-lwip/custom/sys.c
-tun2socks/tun2socks.c
-base/DebugObject.c
-base/BLog.c
-base/BPending.c
-flowextra/PacketPassInactivityMonitor.c
-tun2socks/SocksUdpGwClient.c
-udpgw_client/UdpGwClient.c
-"
-
-set -e
-set -x
-
-OBJS=()
-for f in $SOURCES; do
-    obj=$(basename "${f}").o
-    "${CC}" -c ${CFLAGS} "${INCLUDES[@]}" "${DEFS[@]}" "${SRCDIR}/${f}" -o "${obj}"
-    OBJS=( "${OBJS[@]}" "${obj}" )
-done
-
-"${CC}" ${LDFLAGS} "${OBJS[@]}" -o tun2socks -lrt
diff --git a/external/badvpn_dns/compile-udpgw.sh b/external/badvpn_dns/compile-udpgw.sh
deleted file mode 100755
index 5f132f9..0000000
--- a/external/badvpn_dns/compile-udpgw.sh
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/bin/bash
-#
-# Compiles udpgw for Linux.
-# Intended as a convenience if you don't want to deal with CMake.
-
-# Input environment vars:
-#   SRCDIR - BadVPN source code
-#   CC - compiler
-#   CFLAGS - compiler compile flags
-#   LDFLAGS - compiler link flags
-#   ENDIAN - "little" or "big"
-#   KERNEL - "2.6" or "2.4", default "2.6"
-#
-# Puts object files and the executable in the working directory.
-#
-
-if [[ -z $SRCDIR ]] || [[ ! -e $SRCDIR/CMakeLists.txt ]]; then
-    echo "SRCDIR is wrong"
-    exit 1
-fi
-
-if ! "${CC}" --version &>/dev/null; then
-    echo "CC is wrong"
-    exit 1
-fi
-
-if [[ $ENDIAN != "little" ]] && [[ $ENDIAN != "big" ]]; then
-    echo "ENDIAN is wrong"
-    exit 1
-fi
-
-if [[ -z $KERNEL ]]; then
-    KERNEL="2.6"
-elif [[ $KERNEL != "2.6" ]] && [[ $KERNEL != "2.4" ]]; then
-    echo "KERNEL is wrong"
-    exit 1
-fi
-
-CFLAGS="${CFLAGS} -std=gnu99"
-INCLUDES=( "-I${SRCDIR}" )
-DEFS=( -DBADVPN_THREAD_SAFE=0 -DBADVPN_LINUX -DBADVPN_BREACTOR_BADVPN -D_GNU_SOURCE )
-
-[[ $KERNEL = "2.4" ]] && DEFS=( "${DEFS[@]}" -DBADVPN_USE_SELFPIPE -DBADVPN_USE_POLL ) || DEFS=( "${DEFS[@]}" -DBADVPN_USE_SIGNALFD -DBADVPN_USE_EPOLL )
-
-[[ $ENDIAN = "little" ]] && DEFS=( "${DEFS[@]}" -DBADVPN_LITTLE_ENDIAN ) || DEFS=( "${DEFS[@]}" -DBADVPN_BIG_ENDIAN )
-    
-SOURCES="
-base/BLog_syslog.c
-system/BReactor_badvpn.c
-system/BSignal.c
-system/BConnection_unix.c
-system/BDatagram_unix.c
-system/BTime.c
-system/BUnixSignal.c
-system/BNetwork.c
-flow/StreamRecvInterface.c
-flow/PacketRecvInterface.c
-flow/PacketPassInterface.c
-flow/StreamPassInterface.c
-flow/SinglePacketBuffer.c
-flow/BufferWriter.c
-flow/PacketBuffer.c
-flow/PacketStreamSender.c
-flow/PacketProtoFlow.c
-flow/PacketPassFairQueue.c
-flow/PacketProtoEncoder.c
-flow/PacketProtoDecoder.c
-base/DebugObject.c
-base/BLog.c
-base/BPending.c
-udpgw/udpgw.c
-"
-
-set -e
-set -x
-
-OBJS=()
-for f in $SOURCES; do
-    obj=$(basename "${f}").o
-    "${CC}" -c ${CFLAGS} "${INCLUDES[@]}" "${DEFS[@]}" "${SRCDIR}/${f}" -o "${obj}"
-    OBJS=( "${OBJS[@]}" "${obj}" )
-done
-
-"${CC}" ${LDFLAGS} "${OBJS[@]}" -o udpgw -lrt
diff --git a/external/badvpn_dns/dhcpclient/BDHCPClient.c b/external/badvpn_dns/dhcpclient/BDHCPClient.c
deleted file mode 100644
index 70ee6ad..0000000
--- a/external/badvpn_dns/dhcpclient/BDHCPClient.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/**
- * @file BDHCPClient.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <sys/ioctl.h>
-#include <linux/filter.h>
-
-#include <misc/debug.h>
-#include <misc/byteorder.h>
-#include <misc/ethernet_proto.h>
-#include <misc/ipv4_proto.h>
-#include <misc/udp_proto.h>
-#include <misc/dhcp_proto.h>
-#include <misc/get_iface_info.h>
-#include <base/BLog.h>
-
-#include <dhcpclient/BDHCPClient.h>
-
-#include <generated/blog_channel_BDHCPClient.h>
-
-#define DHCP_SERVER_PORT 67
-#define DHCP_CLIENT_PORT 68
-
-#define IPUDP_OVERHEAD (sizeof(struct ipv4_header) + sizeof(struct udp_header))
-
-static const struct sock_filter dhcp_sock_filter[] = {
-    BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 9),                        // A <- IP protocol
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPV4_PROTOCOL_UDP, 0, 3), // IP protocol = UDP ?
-    BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 22),                       // A <- UDP destination port
-    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_CLIENT_PORT, 0, 1),  // UDP destination port = DHCP client ?
-    BPF_STMT(BPF_RET + BPF_K, 65535),                             // return all
-    BPF_STMT(BPF_RET + BPF_K, 0)                                  // ignore
-};
-
-static void dgram_handler (BDHCPClient *o, int event)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    BLog(BLOG_ERROR, "packet socket error");
-    
-    // report error
-    DEBUGERROR(&o->d_err, o->handler(o->user, BDHCPCLIENT_EVENT_ERROR));
-    return;
-}
-
-static void dhcp_handler (BDHCPClient *o, int event)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    switch (event) {
-        case BDHCPCLIENTCORE_EVENT_UP:
-            ASSERT(!o->up)
-            o->up = 1;
-            o->handler(o->user, BDHCPCLIENT_EVENT_UP);
-            return;
-            
-        case BDHCPCLIENTCORE_EVENT_DOWN:
-            ASSERT(o->up)
-            o->up = 0;
-            o->handler(o->user, BDHCPCLIENT_EVENT_DOWN);
-            return;
-            
-        default:
-            ASSERT(0);
-    }
-}
-
-static void dhcp_func_getsendermac (BDHCPClient *o, uint8_t *out_mac)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    BAddr remote_addr;
-    BIPAddr local_addr;
-    if (!BDatagram_GetLastReceiveAddrs(&o->dgram, &remote_addr, &local_addr)) {
-        BLog(BLOG_ERROR, "BDatagram_GetLastReceiveAddrs failed");
-        goto fail;
-    }
-    
-    if (remote_addr.type != BADDR_TYPE_PACKET) {
-        BLog(BLOG_ERROR, "address type invalid");
-        goto fail;
-    }
-    
-    if (remote_addr.packet.header_type != BADDR_PACKET_HEADER_TYPE_ETHERNET) {
-        BLog(BLOG_ERROR, "address header type invalid");
-        goto fail;
-    }
-    
-    memcpy(out_mac, remote_addr.packet.phys_addr, 6);
-    return;
-    
-fail:
-    memset(out_mac, 0, 6);
-}
-
-int BDHCPClient_Init (BDHCPClient *o, const char *ifname, struct BDHCPClient_opts opts, BReactor *reactor, BRandom2 *random2, BDHCPClient_handler handler, void *user)
-{
-    // init arguments
-    o->reactor = reactor;
-    o->handler = handler;
-    o->user = user;
-    
-    // get interface information
-    uint8_t if_mac[6];
-    int if_mtu;
-    int if_index;
-    if (!badvpn_get_iface_info(ifname, if_mac, &if_mtu, &if_index)) {
-        BLog(BLOG_ERROR, "failed to get interface information");
-        goto fail0;
-    }
-    
-    BLog(BLOG_INFO, "if_mac=%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8" if_mtu=%d if_index=%d",
-          if_mac[0], if_mac[1], if_mac[2], if_mac[3], if_mac[4], if_mac[5], if_mtu, if_index);
-    
-    if (if_mtu < IPUDP_OVERHEAD) {
-        BLog(BLOG_ERROR, "MTU is too small for UDP/IP !?!");
-        goto fail0;
-    }
-    
-    int dhcp_mtu = if_mtu - IPUDP_OVERHEAD;
-    
-    // init dgram
-    if (!BDatagram_Init(&o->dgram, BADDR_TYPE_PACKET, o->reactor, o, (BDatagram_handler)dgram_handler)) {
-        BLog(BLOG_ERROR, "BDatagram_Init failed");
-        goto fail0;
-    }
-    
-    // set socket filter
-    {
-        struct sock_filter filter[sizeof(dhcp_sock_filter) / sizeof(dhcp_sock_filter[0])];
-        memcpy(filter, dhcp_sock_filter, sizeof(filter));
-        struct sock_fprog fprog = {
-            .len = sizeof(filter) / sizeof(filter[0]),
-            .filter = filter
-        };
-        if (setsockopt(BDatagram_GetFd(&o->dgram), SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0) {
-            BLog(BLOG_NOTICE, "not using socket filter");
-        }
-    }
-    
-    // bind dgram
-    BAddr bind_addr;
-    BAddr_InitPacket(&bind_addr, hton16(ETHERTYPE_IPV4), if_index, BADDR_PACKET_HEADER_TYPE_ETHERNET, BADDR_PACKET_PACKET_TYPE_HOST, if_mac);
-    if (!BDatagram_Bind(&o->dgram, bind_addr)) {
-        BLog(BLOG_ERROR, "BDatagram_Bind failed");
-        goto fail1;
-    }
-    
-    // set dgram send addresses
-    BAddr dest_addr;
-    uint8_t broadcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-    BAddr_InitPacket(&dest_addr, hton16(ETHERTYPE_IPV4), if_index, BADDR_PACKET_HEADER_TYPE_ETHERNET, BADDR_PACKET_PACKET_TYPE_BROADCAST, broadcast_mac);
-    BIPAddr local_addr;
-    BIPAddr_InitInvalid(&local_addr);
-    BDatagram_SetSendAddrs(&o->dgram, dest_addr, local_addr);
-
-    // init dgram interfaces
-    BDatagram_SendAsync_Init(&o->dgram, if_mtu);
-    BDatagram_RecvAsync_Init(&o->dgram, if_mtu);
-    
-    // init sending
-    
-    // init copier
-    PacketCopier_Init(&o->send_copier, dhcp_mtu, BReactor_PendingGroup(o->reactor));
-    
-    // init encoder
-    DHCPIpUdpEncoder_Init(&o->send_encoder, PacketCopier_GetOutput(&o->send_copier), BReactor_PendingGroup(o->reactor));
-    
-    // init buffer
-    if (!SinglePacketBuffer_Init(&o->send_buffer, DHCPIpUdpEncoder_GetOutput(&o->send_encoder), BDatagram_SendAsync_GetIf(&o->dgram), BReactor_PendingGroup(o->reactor))) {
-        BLog(BLOG_ERROR, "SinglePacketBuffer_Init failed");
-        goto fail2;
-    }
-    
-    // init receiving
-    
-    // init copier
-    PacketCopier_Init(&o->recv_copier, dhcp_mtu, BReactor_PendingGroup(o->reactor));
-    
-    // init decoder
-    DHCPIpUdpDecoder_Init(&o->recv_decoder, PacketCopier_GetInput(&o->recv_copier), BReactor_PendingGroup(o->reactor));
-    
-    // init buffer
-    if (!SinglePacketBuffer_Init(&o->recv_buffer, BDatagram_RecvAsync_GetIf(&o->dgram), DHCPIpUdpDecoder_GetInput(&o->recv_decoder), BReactor_PendingGroup(o->reactor))) {
-        BLog(BLOG_ERROR, "SinglePacketBuffer_Init failed");
-        goto fail3;
-    }
-    
-    // init options
-    struct BDHCPClientCore_opts core_opts;
-    core_opts.hostname = opts.hostname;
-    core_opts.vendorclassid = opts.vendorclassid;
-    core_opts.clientid = opts.clientid;
-    core_opts.clientid_len = opts.clientid_len;
-    
-    // auto-generate clientid from MAC if requested
-    uint8_t mac_cid[7];
-    if (opts.auto_clientid) {
-        mac_cid[0] = DHCP_HARDWARE_ADDRESS_TYPE_ETHERNET;
-        memcpy(mac_cid + 1, if_mac, 6);
-        core_opts.clientid = mac_cid;
-        core_opts.clientid_len = sizeof(mac_cid);
-    }
-    
-    // init dhcp
-    if (!BDHCPClientCore_Init(&o->dhcp, PacketCopier_GetInput(&o->send_copier), PacketCopier_GetOutput(&o->recv_copier), if_mac, core_opts, o->reactor, random2, o,
-                              (BDHCPClientCore_func_getsendermac)dhcp_func_getsendermac,
-                              (BDHCPClientCore_handler)dhcp_handler
-    )) {
-        BLog(BLOG_ERROR, "BDHCPClientCore_Init failed");
-        goto fail4;
-    }
-    
-    // set not up
-    o->up = 0;
-    
-    DebugError_Init(&o->d_err, BReactor_PendingGroup(o->reactor));
-    DebugObject_Init(&o->d_obj);
-    return 1;
-    
-fail4:
-    SinglePacketBuffer_Free(&o->recv_buffer);
-fail3:
-    DHCPIpUdpDecoder_Free(&o->recv_decoder);
-    PacketCopier_Free(&o->recv_copier);
-    SinglePacketBuffer_Free(&o->send_buffer);
-fail2:
-    DHCPIpUdpEncoder_Free(&o->send_encoder);
-    PacketCopier_Free(&o->send_copier);
-    BDatagram_RecvAsync_Free(&o->dgram);
-    BDatagram_SendAsync_Free(&o->dgram);
-fail1:
-    BDatagram_Free(&o->dgram);
-fail0:
-    return 0;
-}
-
-void BDHCPClient_Free (BDHCPClient *o)
-{
-    DebugObject_Free(&o->d_obj);
-    DebugError_Free(&o->d_err);
-    
-    // free dhcp
-    BDHCPClientCore_Free(&o->dhcp);
-    
-    // free receiving
-    SinglePacketBuffer_Free(&o->recv_buffer);
-    DHCPIpUdpDecoder_Free(&o->recv_decoder);
-    PacketCopier_Free(&o->recv_copier);
-    
-    // free sending
-    SinglePacketBuffer_Free(&o->send_buffer);
-    DHCPIpUdpEncoder_Free(&o->send_encoder);
-    PacketCopier_Free(&o->send_copier);
-    
-    // free dgram interfaces
-    BDatagram_RecvAsync_Free(&o->dgram);
-    BDatagram_SendAsync_Free(&o->dgram);
-    
-    // free dgram
-    BDatagram_Free(&o->dgram);
-}
-
-int BDHCPClient_IsUp (BDHCPClient *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return o->up;
-}
-
-void BDHCPClient_GetClientIP (BDHCPClient *o, uint32_t *out_ip)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->up)
-    
-    BDHCPClientCore_GetClientIP(&o->dhcp, out_ip);
-}
-
-void BDHCPClient_GetClientMask (BDHCPClient *o, uint32_t *out_mask)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->up)
-    
-    BDHCPClientCore_GetClientMask(&o->dhcp, out_mask);
-}
-
-int BDHCPClient_GetRouter (BDHCPClient *o, uint32_t *out_router)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->up)
-    
-    return BDHCPClientCore_GetRouter(&o->dhcp, out_router);
-}
-
-int BDHCPClient_GetDNS (BDHCPClient *o, uint32_t *out_dns_servers, size_t max_dns_servers)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->up)
-    
-    return BDHCPClientCore_GetDNS(&o->dhcp, out_dns_servers, max_dns_servers);
-}
-
-void BDHCPClient_GetServerMAC (BDHCPClient *o, uint8_t *out_mac)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->up)
-    
-    BDHCPClientCore_GetServerMAC(&o->dhcp, out_mac);
-}
diff --git a/external/badvpn_dns/dhcpclient/BDHCPClient.h b/external/badvpn_dns/dhcpclient/BDHCPClient.h
deleted file mode 100644
index c0da0c4..0000000
--- a/external/badvpn_dns/dhcpclient/BDHCPClient.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * @file BDHCPClient.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * DHCP client.
- */
-
-#ifndef BADVPN_DHCPCLIENT_BDHCPCLIENT_H
-#define BADVPN_DHCPCLIENT_BDHCPCLIENT_H
-
-#include <base/DebugObject.h>
-#include <system/BDatagram.h>
-#include <flow/PacketCopier.h>
-#include <flow/SinglePacketBuffer.h>
-#include <dhcpclient/BDHCPClientCore.h>
-#include <dhcpclient/DHCPIpUdpDecoder.h>
-#include <dhcpclient/DHCPIpUdpEncoder.h>
-
-#define BDHCPCLIENT_EVENT_UP 1
-#define BDHCPCLIENT_EVENT_DOWN 2
-#define BDHCPCLIENT_EVENT_ERROR 3
-
-#define BDHCPCLIENT_MAX_DOMAIN_NAME_SERVERS BDHCPCLIENTCORE_MAX_DOMAIN_NAME_SERVERS
-
-typedef void (*BDHCPClient_handler) (void *user, int event);
-
-typedef struct {
-    BReactor *reactor;
-    BDatagram dgram;
-    BDHCPClient_handler handler;
-    void *user;
-    PacketCopier send_copier;
-    DHCPIpUdpEncoder send_encoder;
-    SinglePacketBuffer send_buffer;
-    SinglePacketBuffer recv_buffer;
-    DHCPIpUdpDecoder recv_decoder;
-    PacketCopier recv_copier;
-    BDHCPClientCore dhcp;
-    int up;
-    DebugError d_err;
-    DebugObject d_obj;
-} BDHCPClient;
-
-struct BDHCPClient_opts {
-    const char *hostname;
-    const char *vendorclassid;
-    const uint8_t *clientid;
-    size_t clientid_len;
-    int auto_clientid;
-};
-
-int BDHCPClient_Init (BDHCPClient *o, const char *ifname, struct BDHCPClient_opts opts, BReactor *reactor, BRandom2 *random2, BDHCPClient_handler handler, void *user);
-void BDHCPClient_Free (BDHCPClient *o);
-int BDHCPClient_IsUp (BDHCPClient *o);
-void BDHCPClient_GetClientIP (BDHCPClient *o, uint32_t *out_ip);
-void BDHCPClient_GetClientMask (BDHCPClient *o, uint32_t *out_mask);
-int BDHCPClient_GetRouter (BDHCPClient *o, uint32_t *out_router);
-int BDHCPClient_GetDNS (BDHCPClient *o, uint32_t *out_dns_servers, size_t max_dns_servers);
-void BDHCPClient_GetServerMAC (BDHCPClient *o, uint8_t *out_mac);
-
-#endif
diff --git a/external/badvpn_dns/dhcpclient/BDHCPClientCore.c b/external/badvpn_dns/dhcpclient/BDHCPClientCore.c
deleted file mode 100644
index 5a605e4..0000000
--- a/external/badvpn_dns/dhcpclient/BDHCPClientCore.c
+++ /dev/null
@@ -1,860 +0,0 @@
-/**
- * @file BDHCPClientCore.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-#include <stdlib.h>
-
-#include <misc/byteorder.h>
-#include <misc/minmax.h>
-#include <misc/balloc.h>
-#include <misc/bsize.h>
-#include <misc/dhcp_proto.h>
-#include <base/BLog.h>
-
-#include <dhcpclient/BDHCPClientCore.h>
-
-#include <generated/blog_channel_BDHCPClientCore.h>
-
-#define RESET_TIMEOUT 4000
-#define REQUEST_TIMEOUT 3000
-#define RENEW_REQUEST_TIMEOUT 20000
-#define MAX_REQUESTS 4
-#define RENEW_TIMEOUT(lease) ((btime_t)500 * (lease))
-#define XID_REUSE_MAX 8
-
-#define LEASE_TIMEOUT(lease) ((btime_t)1000 * (lease) - RENEW_TIMEOUT(lease))
-
-#define STATE_RESETTING 1
-#define STATE_SENT_DISCOVER 2
-#define STATE_SENT_REQUEST 3
-#define STATE_FINISHED 4
-#define STATE_RENEWING 5
-
-#define IP_UDP_HEADERS_SIZE 28
-
-static void report_up (BDHCPClientCore *o)
-{
-    o->handler(o->user, BDHCPCLIENTCORE_EVENT_UP);
-    return;
-}
-
-static void report_down (BDHCPClientCore *o)
-{
-    o->handler(o->user, BDHCPCLIENTCORE_EVENT_DOWN);
-    return;
-}
-
-static void send_message (
-    BDHCPClientCore *o,
-    int type,
-    uint32_t xid,
-    int have_requested_ip_address, uint32_t requested_ip_address,
-    int have_dhcp_server_identifier, uint32_t dhcp_server_identifier
-)
-{
-    ASSERT(type == DHCP_MESSAGE_TYPE_DISCOVER || type == DHCP_MESSAGE_TYPE_REQUEST)
-    
-    if (o->sending) {
-        BLog(BLOG_ERROR, "already sending");
-        return;
-    }
-    
-    // write header
-    struct dhcp_header header;
-    memset(&header, 0, sizeof(header));
-    header.op = hton8(DHCP_OP_BOOTREQUEST);
-    header.htype = hton8(DHCP_HARDWARE_ADDRESS_TYPE_ETHERNET);
-    header.hlen = hton8(6);
-    header.xid = xid;
-    header.secs = hton16(0);
-    memcpy(header.chaddr, o->client_mac_addr, sizeof(o->client_mac_addr));
-    header.magic = hton32(DHCP_MAGIC);
-    memcpy(o->send_buf, &header, sizeof(header));
-    
-    // write options
-    
-    char *out = o->send_buf + sizeof(header);
-    struct dhcp_option_header oh;
-    
-    // DHCP message type
-    {
-        oh.type = hton8(DHCP_OPTION_DHCP_MESSAGE_TYPE);
-        oh.len = hton8(sizeof(struct dhcp_option_dhcp_message_type));
-        struct dhcp_option_dhcp_message_type opt;
-        opt.type = hton8(type);
-        memcpy(out, &oh, sizeof(oh));
-        memcpy(out + sizeof(oh), &opt, sizeof(opt));
-        out += sizeof(oh) + sizeof(opt);
-    }
-    
-    if (have_requested_ip_address) {
-        // requested IP address
-        oh.type = hton8(DHCP_OPTION_REQUESTED_IP_ADDRESS);
-        oh.len = hton8(sizeof(struct dhcp_option_addr));
-        struct dhcp_option_addr opt;
-        opt.addr = requested_ip_address;
-        memcpy(out, &oh, sizeof(oh));
-        memcpy(out + sizeof(oh), &opt, sizeof(opt));
-        out += sizeof(oh) + sizeof(opt);
-    }
-    
-    if (have_dhcp_server_identifier) {
-        // DHCP server identifier
-        oh.type = hton8(DHCP_OPTION_DHCP_SERVER_IDENTIFIER);
-        oh.len = hton8(sizeof(struct dhcp_option_dhcp_server_identifier));
-        struct dhcp_option_dhcp_server_identifier opt;
-        opt.id = dhcp_server_identifier;
-        memcpy(out, &oh, sizeof(oh));
-        memcpy(out + sizeof(oh), &opt, sizeof(opt));
-        out += sizeof(oh) + sizeof(opt);
-    }
-    
-    // maximum message size
-    {
-        oh.type = hton8(DHCP_OPTION_MAXIMUM_MESSAGE_SIZE);
-        oh.len = hton8(sizeof(struct dhcp_option_maximum_message_size));
-        struct dhcp_option_maximum_message_size opt;
-        opt.size = hton16(IP_UDP_HEADERS_SIZE + PacketRecvInterface_GetMTU(o->recv_if));
-        memcpy(out, &oh, sizeof(oh));
-        memcpy(out + sizeof(oh), &opt, sizeof(opt));
-        out += sizeof(oh) + sizeof(opt);
-    }
-    
-    // parameter request list
-    {
-        oh.type = hton8(DHCP_OPTION_PARAMETER_REQUEST_LIST);
-        oh.len = hton8(4);
-        uint8_t opt[4];
-        opt[0] = DHCP_OPTION_SUBNET_MASK;
-        opt[1] = DHCP_OPTION_ROUTER;
-        opt[2] = DHCP_OPTION_DOMAIN_NAME_SERVER;
-        opt[3] = DHCP_OPTION_IP_ADDRESS_LEASE_TIME;
-        memcpy(out, &oh, sizeof(oh));
-        memcpy(out + sizeof(oh), &opt, sizeof(opt));
-        out += sizeof(oh) + sizeof(opt);
-    }
-    
-    if (o->hostname) {
-        // host name
-        oh.type = hton8(DHCP_OPTION_HOST_NAME);
-        oh.len = hton8(strlen(o->hostname));
-        memcpy(out, &oh, sizeof(oh));
-        memcpy(out + sizeof(oh), o->hostname, strlen(o->hostname));
-        out += sizeof(oh) + strlen(o->hostname);
-    }
-    
-    if (o->vendorclassid) {
-        // vendor class identifier
-        oh.type = hton8(DHCP_OPTION_VENDOR_CLASS_IDENTIFIER);
-        oh.len = hton8(strlen(o->vendorclassid));
-        memcpy(out, &oh, sizeof(oh));
-        memcpy(out + sizeof(oh), o->vendorclassid, strlen(o->vendorclassid));
-        out += sizeof(oh) + strlen(o->vendorclassid);
-    }
-    
-    if (o->clientid) {
-        // client identifier
-        oh.type = hton8(DHCP_OPTION_CLIENT_IDENTIFIER);
-        oh.len = hton8(o->clientid_len);
-        memcpy(out, &oh, sizeof(oh));
-        memcpy(out + sizeof(oh), o->clientid, o->clientid_len);
-        out += sizeof(oh) + o->clientid_len;
-    }
-    
-    // end option
-    uint8_t end = 0xFF;
-    memcpy(out, &end, sizeof(end));
-    out += sizeof(end);
-    
-    // send it
-    PacketPassInterface_Sender_Send(o->send_if, (uint8_t *)o->send_buf, out - o->send_buf);
-    o->sending = 1;
-}
-
-static void send_handler_done (BDHCPClientCore *o)
-{
-    ASSERT(o->sending)
-    DebugObject_Access(&o->d_obj);
-    
-    o->sending = 0;
-}
-
-static void recv_handler_done (BDHCPClientCore *o, int data_len)
-{
-    ASSERT(data_len >= 0)
-    DebugObject_Access(&o->d_obj);
-    
-    // receive more packets
-    PacketRecvInterface_Receiver_Recv(o->recv_if, (uint8_t *)o->recv_buf);
-    
-    if (o->state == STATE_RESETTING) {
-        return;
-    }
-    
-    // check header
-    
-    if (data_len < sizeof(struct dhcp_header)) {
-        return;
-    }
-    
-    struct dhcp_header header;
-    memcpy(&header, o->recv_buf, sizeof(header));
-    
-    if (ntoh8(header.op) != DHCP_OP_BOOTREPLY) {
-        return;
-    }
-    
-    if (ntoh8(header.htype) != DHCP_HARDWARE_ADDRESS_TYPE_ETHERNET) {
-        return;
-    }
-    
-    if (ntoh8(header.hlen) != 6) {
-        return;
-    }
-    
-    if (header.xid != o->xid) {
-        return;
-    }
-    
-    if (memcmp(header.chaddr, o->client_mac_addr, sizeof(o->client_mac_addr))) {
-        return;
-    }
-    
-    if (ntoh32(header.magic) != DHCP_MAGIC) {
-        return;
-    }
-    
-    // parse and check options
-    
-    uint8_t *pos = (uint8_t *)o->recv_buf + sizeof(header);
-    int len = data_len - sizeof(header);
-    
-    int have_end = 0;
-    
-    int dhcp_message_type = -1;
-    
-    int have_dhcp_server_identifier = 0;
-    uint32_t dhcp_server_identifier = 0; // to remove warning
-    
-    int have_ip_address_lease_time = 0;
-    uint32_t ip_address_lease_time = 0; // to remove warning
-    
-    int have_subnet_mask = 0;
-    uint32_t subnet_mask = 0; // to remove warning
-    
-    int have_router = 0;
-    uint32_t router = 0; // to remove warning
-    
-    int domain_name_servers_count = 0;
-    uint32_t domain_name_servers[BDHCPCLIENTCORE_MAX_DOMAIN_NAME_SERVERS];
-    
-    while (len > 0) {
-        // padding option ?
-        if (*pos == 0) {
-            pos++;
-            len--;
-            continue;
-        }
-        
-        if (have_end) {
-            return;
-        }
-        
-        // end option ?
-        if (*pos == 0xff) {
-            pos++;
-            len--;
-            have_end = 1;
-            continue;
-        }
-        
-        // check option header
-        if (len < sizeof(struct dhcp_option_header)) {
-            return;
-        }
-        struct dhcp_option_header opt;
-        memcpy(&opt, pos, sizeof(opt));
-        pos += sizeof(opt);
-        len -= sizeof(opt);
-        int opt_type = ntoh8(opt.type);
-        int opt_len = ntoh8(opt.len);
-        
-        // check option payload
-        if (opt_len > len) {
-            return;
-        }
-        uint8_t *optval = pos;
-        pos += opt_len;
-        len -= opt_len;
-        
-        switch (opt_type) {
-            case DHCP_OPTION_DHCP_MESSAGE_TYPE: {
-                if (opt_len != sizeof(struct dhcp_option_dhcp_message_type)) {
-                    return;
-                }
-                struct dhcp_option_dhcp_message_type val;
-                memcpy(&val, optval, sizeof(val));
-                
-                dhcp_message_type = ntoh8(val.type);
-            } break;
-            
-            case DHCP_OPTION_DHCP_SERVER_IDENTIFIER: {
-                if (opt_len != sizeof(struct dhcp_option_dhcp_server_identifier)) {
-                    return;
-                }
-                struct dhcp_option_dhcp_server_identifier val;
-                memcpy(&val, optval, sizeof(val));
-                
-                dhcp_server_identifier = val.id;
-                have_dhcp_server_identifier = 1;
-            } break;
-            
-            case DHCP_OPTION_IP_ADDRESS_LEASE_TIME: {
-                if (opt_len != sizeof(struct dhcp_option_time)) {
-                    return;
-                }
-                struct dhcp_option_time val;
-                memcpy(&val, optval, sizeof(val));
-                
-                ip_address_lease_time = ntoh32(val.time);
-                have_ip_address_lease_time = 1;
-            } break;
-            
-            case DHCP_OPTION_SUBNET_MASK: {
-                if (opt_len != sizeof(struct dhcp_option_addr)) {
-                    return;
-                }
-                struct dhcp_option_addr val;
-                memcpy(&val, optval, sizeof(val));
-                
-                subnet_mask = val.addr;
-                have_subnet_mask = 1;
-            } break;
-            
-            case DHCP_OPTION_ROUTER: {
-                if (opt_len != sizeof(struct dhcp_option_addr)) {
-                    return;
-                }
-                struct dhcp_option_addr val;
-                memcpy(&val, optval, sizeof(val));
-                
-                router = val.addr;
-                have_router = 1;
-            } break;
-            
-            case DHCP_OPTION_DOMAIN_NAME_SERVER: {
-                if (opt_len % sizeof(struct dhcp_option_addr)) {
-                    return;
-                }
-                
-                int num_servers = opt_len / sizeof(struct dhcp_option_addr);
-                
-                int i;
-                for (i = 0; i < num_servers && i < BDHCPCLIENTCORE_MAX_DOMAIN_NAME_SERVERS; i++) {
-                    struct dhcp_option_addr addr;
-                    memcpy(&addr, optval + i * sizeof(addr), sizeof(addr));
-                    domain_name_servers[i] = addr.addr;
-                }
-                
-                domain_name_servers_count = i;
-            } break;
-        }
-    }
-    
-    if (!have_end) {
-        return;
-    }
-    
-    if (dhcp_message_type == -1) {
-        return;
-    }
-    
-    if (dhcp_message_type != DHCP_MESSAGE_TYPE_OFFER && dhcp_message_type != DHCP_MESSAGE_TYPE_ACK && dhcp_message_type != DHCP_MESSAGE_TYPE_NAK) {
-        return;
-    }
-    
-    if (!have_dhcp_server_identifier) {
-        return;
-    }
-    
-    if (dhcp_message_type == DHCP_MESSAGE_TYPE_NAK) {
-        if (o->state != STATE_SENT_REQUEST && o->state != STATE_FINISHED && o->state != STATE_RENEWING) {
-            return;
-        }
-        
-        if (dhcp_server_identifier != o->offered.dhcp_server_identifier) {
-            return;
-        }
-        
-        if (o->state == STATE_SENT_REQUEST) {
-            BLog(BLOG_INFO, "received NAK (in sent request)");
-            
-            // stop request timer
-            BReactor_RemoveTimer(o->reactor, &o->request_timer);
-            
-            // start reset timer
-            BReactor_SetTimer(o->reactor, &o->reset_timer);
-            
-            // set state
-            o->state = STATE_RESETTING;
-        }
-        else if (o->state == STATE_FINISHED) {
-            BLog(BLOG_INFO, "received NAK (in finished)");
-            
-            // stop renew timer
-            BReactor_RemoveTimer(o->reactor, &o->renew_timer);
-            
-            // start reset timer
-            BReactor_SetTimer(o->reactor, &o->reset_timer);
-            
-            // set state
-            o->state = STATE_RESETTING;
-            
-            // report to user
-            report_down(o);
-            return;
-        }
-        else { // STATE_RENEWING
-            BLog(BLOG_INFO, "received NAK (in renewing)");
-            
-            // stop renew request timer
-            BReactor_RemoveTimer(o->reactor, &o->renew_request_timer);
-            
-            // stop lease timer
-            BReactor_RemoveTimer(o->reactor, &o->lease_timer);
-            
-            // start reset timer
-            BReactor_SetTimer(o->reactor, &o->reset_timer);
-            
-            // set state
-            o->state = STATE_RESETTING;
-            
-            // report to user
-            report_down(o);
-            return;
-        }
-        
-        return;
-    }
-    
-    if (ntoh32(header.yiaddr) == 0) {
-        return;
-    }
-    
-    if (!have_ip_address_lease_time) {
-        return;
-    }
-    
-    if (!have_subnet_mask) {
-        return;
-    }
-    
-    if (o->state == STATE_SENT_DISCOVER && dhcp_message_type == DHCP_MESSAGE_TYPE_OFFER) {
-        BLog(BLOG_INFO, "received OFFER");
-        
-        // remember offer
-        o->offered.yiaddr = header.yiaddr;
-        o->offered.dhcp_server_identifier = dhcp_server_identifier;
-        
-        // send request
-        send_message(o, DHCP_MESSAGE_TYPE_REQUEST, o->xid, 1, o->offered.yiaddr, 1, o->offered.dhcp_server_identifier);
-        
-        // stop reset timer
-        BReactor_RemoveTimer(o->reactor, &o->reset_timer);
-        
-        // start request timer
-        BReactor_SetTimer(o->reactor, &o->request_timer);
-        
-        // set state
-        o->state = STATE_SENT_REQUEST;
-        
-        // set request count
-        o->request_count = 1;
-    }
-    else if (o->state == STATE_SENT_REQUEST && dhcp_message_type == DHCP_MESSAGE_TYPE_ACK) {
-        if (header.yiaddr != o->offered.yiaddr) {
-            return;
-        }
-        
-        if (dhcp_server_identifier != o->offered.dhcp_server_identifier) {
-            return;
-        }
-        
-        BLog(BLOG_INFO, "received ACK (in sent request)");
-        
-        // remember stuff
-        o->acked.ip_address_lease_time = ip_address_lease_time;
-        o->acked.subnet_mask = subnet_mask;
-        o->acked.have_router = have_router;
-        if (have_router) {
-            o->acked.router = router;
-        }
-        o->acked.domain_name_servers_count = domain_name_servers_count;
-        memcpy(o->acked.domain_name_servers, domain_name_servers, domain_name_servers_count * sizeof(uint32_t));
-        o->func_getsendermac(o->user, o->acked.server_mac);
-        
-        // stop request timer
-        BReactor_RemoveTimer(o->reactor, &o->request_timer);
-        
-        // start renew timer
-        BReactor_SetTimerAfter(o->reactor, &o->renew_timer, RENEW_TIMEOUT(o->acked.ip_address_lease_time));
-        
-        // set state
-        o->state = STATE_FINISHED;
-        
-        // report to user
-        report_up(o);
-        return;
-    }
-    else if (o->state == STATE_RENEWING && dhcp_message_type == DHCP_MESSAGE_TYPE_ACK) {
-        if (header.yiaddr != o->offered.yiaddr) {
-            return;
-        }
-        
-        if (dhcp_server_identifier != o->offered.dhcp_server_identifier) {
-            return;
-        }
-        
-        // TODO: check parameters?
-        
-        BLog(BLOG_INFO, "received ACK (in renewing)");
-        
-        // remember stuff
-        o->acked.ip_address_lease_time = ip_address_lease_time;
-        
-        // stop renew request timer
-        BReactor_RemoveTimer(o->reactor, &o->renew_request_timer);
-        
-        // stop lease timer
-        BReactor_RemoveTimer(o->reactor, &o->lease_timer);
-        
-        // start renew timer
-        BReactor_SetTimerAfter(o->reactor, &o->renew_timer, RENEW_TIMEOUT(o->acked.ip_address_lease_time));
-        
-        // set state
-        o->state = STATE_FINISHED;
-    }
-}
-
-static void start_process (BDHCPClientCore *o, int force_new_xid)
-{
-    if (force_new_xid || o->xid_reuse_counter == XID_REUSE_MAX) {
-        // generate xid
-        if (!BRandom2_GenBytes(o->random2, &o->xid, sizeof(o->xid))) {
-            BLog(BLOG_ERROR, "BRandom2_GenBytes failed");
-            o->xid = UINT32_C(3416960072);
-        }
-        
-        // reset counter
-        o->xid_reuse_counter = 0;
-    }
-    
-    // increment counter
-    o->xid_reuse_counter++;
-    
-    // send discover
-    send_message(o, DHCP_MESSAGE_TYPE_DISCOVER, o->xid, 0, 0, 0, 0);
-    
-    // set timer
-    BReactor_SetTimer(o->reactor, &o->reset_timer);
-    
-    // set state
-    o->state = STATE_SENT_DISCOVER;
-}
-
-static void reset_timer_handler (BDHCPClientCore *o)
-{
-    ASSERT(o->state == STATE_RESETTING || o->state == STATE_SENT_DISCOVER)
-    DebugObject_Access(&o->d_obj);
-    
-    BLog(BLOG_INFO, "reset timer");
-    
-    start_process(o, (o->state == STATE_RESETTING));
-}
-
-static void request_timer_handler (BDHCPClientCore *o)
-{
-    ASSERT(o->state == STATE_SENT_REQUEST)
-    ASSERT(o->request_count >= 1)
-    ASSERT(o->request_count <= MAX_REQUESTS)
-    DebugObject_Access(&o->d_obj);
-    
-    // if we have sent enough requests, start again
-    if (o->request_count == MAX_REQUESTS) {
-        BLog(BLOG_INFO, "request timer, aborting");
-        
-        start_process(o, 0);
-        return;
-    }
-    
-    BLog(BLOG_INFO, "request timer, retrying");
-    
-    // send request
-    send_message(o, DHCP_MESSAGE_TYPE_REQUEST, o->xid, 1, o->offered.yiaddr, 1, o->offered.dhcp_server_identifier);
-    
-    // start request timer
-    BReactor_SetTimer(o->reactor, &o->request_timer);
-    
-    // increment request count
-    o->request_count++;
-}
-
-static void renew_timer_handler (BDHCPClientCore *o)
-{
-    ASSERT(o->state == STATE_FINISHED)
-    DebugObject_Access(&o->d_obj);
-    
-    BLog(BLOG_INFO, "renew timer");
-    
-    // send request
-    send_message(o, DHCP_MESSAGE_TYPE_REQUEST, o->xid, 1, o->offered.yiaddr, 0, 0);
-    
-    // start renew request timer
-    BReactor_SetTimer(o->reactor, &o->renew_request_timer);
-    
-    // start lease timer
-    BReactor_SetTimerAfter(o->reactor, &o->lease_timer, LEASE_TIMEOUT(o->acked.ip_address_lease_time));
-    
-    // set state
-    o->state = STATE_RENEWING;
-}
-
-static void renew_request_timer_handler (BDHCPClientCore *o)
-{
-    ASSERT(o->state == STATE_RENEWING)
-    DebugObject_Access(&o->d_obj);
-    
-    BLog(BLOG_INFO, "renew request timer");
-    
-    // send request
-    send_message(o, DHCP_MESSAGE_TYPE_REQUEST, o->xid, 1, o->offered.yiaddr, 0, 0);
-    
-    // start renew request timer
-    BReactor_SetTimer(o->reactor, &o->renew_request_timer);
-}
-
-static void lease_timer_handler (BDHCPClientCore *o)
-{
-    ASSERT(o->state == STATE_RENEWING)
-    DebugObject_Access(&o->d_obj);
-    
-    BLog(BLOG_INFO, "lease timer");
-    
-    // stop renew request timer
-    BReactor_RemoveTimer(o->reactor, &o->renew_request_timer);
-    
-    // start again now
-    start_process(o, 1);
-    
-    // report to user
-    report_down(o);
-    return;
-}
-
-static bsize_t maybe_len (const char *str)
-{
-    return bsize_fromsize(str ? strlen(str) : 0);
-}
-
-int BDHCPClientCore_Init (BDHCPClientCore *o, PacketPassInterface *send_if, PacketRecvInterface *recv_if,
-                          uint8_t *client_mac_addr, struct BDHCPClientCore_opts opts, BReactor *reactor,
-                          BRandom2 *random2, void *user,
-                          BDHCPClientCore_func_getsendermac func_getsendermac,
-                          BDHCPClientCore_handler handler)
-{
-    ASSERT(PacketPassInterface_GetMTU(send_if) == PacketRecvInterface_GetMTU(recv_if))
-    ASSERT(PacketPassInterface_GetMTU(send_if) >= 576 - IP_UDP_HEADERS_SIZE)
-    ASSERT(func_getsendermac)
-    ASSERT(handler)
-    
-    // init arguments
-    o->send_if = send_if;
-    o->recv_if = recv_if;
-    memcpy(o->client_mac_addr, client_mac_addr, sizeof(o->client_mac_addr));
-    o->reactor = reactor;
-    o->random2 = random2;
-    o->user = user;
-    o->func_getsendermac = func_getsendermac;
-    o->handler = handler;
-    
-    o->hostname = NULL;
-    o->vendorclassid = NULL;
-    o->clientid = NULL;
-    o->clientid_len = 0;
-    
-    // copy options
-    if (opts.hostname && !(o->hostname = strdup(opts.hostname))) {
-        BLog(BLOG_ERROR, "strdup failed");
-        goto fail0;
-    }
-    if (opts.vendorclassid && !(o->vendorclassid = strdup(opts.vendorclassid))) {
-        BLog(BLOG_ERROR, "strdup failed");
-        goto fail0;
-    }
-    if (opts.clientid) {
-        if (!(o->clientid = BAlloc(opts.clientid_len))) {
-            BLog(BLOG_ERROR, "BAlloc failed");
-            goto fail0;
-        }
-        memcpy(o->clientid, opts.clientid, opts.clientid_len);
-        o->clientid_len = opts.clientid_len;
-    }
-    
-    // make sure options aren't too long
-    bsize_t opts_size = bsize_add(maybe_len(o->hostname), bsize_add(maybe_len(o->vendorclassid), bsize_fromsize(o->clientid_len)));
-    if (opts_size.is_overflow || opts_size.value > 100) {
-        BLog(BLOG_ERROR, "options too long together");
-        goto fail0;
-    }
-    if (o->hostname && strlen(o->hostname) > 255) {
-        BLog(BLOG_ERROR, "hostname too long");
-        goto fail0;
-    }
-    if (o->vendorclassid && strlen(o->vendorclassid) > 255) {
-        BLog(BLOG_ERROR, "vendorclassid too long");
-        goto fail0;
-    }
-    if (o->clientid && o->clientid_len > 255) {
-        BLog(BLOG_ERROR, "clientid too long");
-        goto fail0;
-    }
-    
-    // allocate buffers
-    if (!(o->send_buf = BAlloc(PacketPassInterface_GetMTU(send_if)))) {
-        BLog(BLOG_ERROR, "BAlloc send buf failed");
-        goto fail0;
-    }
-    if (!(o->recv_buf = BAlloc(PacketRecvInterface_GetMTU(recv_if)))) {
-        BLog(BLOG_ERROR, "BAlloc recv buf failed");
-        goto fail1;
-    }
-    
-    // init send interface
-    PacketPassInterface_Sender_Init(o->send_if, (PacketPassInterface_handler_done)send_handler_done, o);
-    
-    // init receive interface
-    PacketRecvInterface_Receiver_Init(o->recv_if, (PacketRecvInterface_handler_done)recv_handler_done, o);
-    
-    // set not sending
-    o->sending = 0;
-    
-    // init timers
-    BTimer_Init(&o->reset_timer, RESET_TIMEOUT, (BTimer_handler)reset_timer_handler, o);
-    BTimer_Init(&o->request_timer, REQUEST_TIMEOUT, (BTimer_handler)request_timer_handler, o);
-    BTimer_Init(&o->renew_timer, 0, (BTimer_handler)renew_timer_handler, o);
-    BTimer_Init(&o->renew_request_timer, RENEW_REQUEST_TIMEOUT, (BTimer_handler)renew_request_timer_handler, o);
-    BTimer_Init(&o->lease_timer, 0, (BTimer_handler)lease_timer_handler, o);
-    
-    // start receving
-    PacketRecvInterface_Receiver_Recv(o->recv_if, (uint8_t *)o->recv_buf);
-    
-    // start
-    start_process(o, 1);
-    
-    DebugObject_Init(&o->d_obj);
-    
-    return 1;
-    
-fail1:
-    BFree(o->send_buf);
-fail0:
-    BFree(o->clientid);
-    free(o->vendorclassid);
-    free(o->hostname);
-    return 0;
-}
-
-void BDHCPClientCore_Free (BDHCPClientCore *o)
-{
-    DebugObject_Free(&o->d_obj);
-    
-    // free timers
-    BReactor_RemoveTimer(o->reactor, &o->lease_timer);
-    BReactor_RemoveTimer(o->reactor, &o->renew_request_timer);
-    BReactor_RemoveTimer(o->reactor, &o->renew_timer);
-    BReactor_RemoveTimer(o->reactor, &o->request_timer);
-    BReactor_RemoveTimer(o->reactor, &o->reset_timer);
-    
-    // free buffers
-    BFree(o->recv_buf);
-    BFree(o->send_buf);
-    
-    // free options
-    BFree(o->clientid);
-    free(o->vendorclassid);
-    free(o->hostname);
-}
-
-void BDHCPClientCore_GetClientIP (BDHCPClientCore *o, uint32_t *out_ip)
-{
-    ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
-    DebugObject_Access(&o->d_obj);
-    
-    *out_ip = o->offered.yiaddr;
-}
-
-void BDHCPClientCore_GetClientMask (BDHCPClientCore *o, uint32_t *out_mask)
-{
-    ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
-    DebugObject_Access(&o->d_obj);
-    
-    *out_mask = o->acked.subnet_mask;
-}
-
-int BDHCPClientCore_GetRouter (BDHCPClientCore *o, uint32_t *out_router)
-{
-    ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
-    DebugObject_Access(&o->d_obj);
-    
-    if (!o->acked.have_router) {
-        return 0;
-    }
-    
-    *out_router = o->acked.router;
-    return 1;
-}
-
-int BDHCPClientCore_GetDNS (BDHCPClientCore *o, uint32_t *out_dns_servers, size_t max_dns_servers)
-{
-    ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
-    DebugObject_Access(&o->d_obj);
-    
-    int num_return = bmin_int(o->acked.domain_name_servers_count, max_dns_servers);
-    
-    memcpy(out_dns_servers, o->acked.domain_name_servers, num_return * sizeof(uint32_t));
-    return num_return;
-}
-
-void BDHCPClientCore_GetServerMAC (BDHCPClientCore *o, uint8_t *out_mac)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->state == STATE_FINISHED || o->state == STATE_RENEWING)
-    
-    memcpy(out_mac, o->acked.server_mac, 6);
-}
diff --git a/external/badvpn_dns/dhcpclient/BDHCPClientCore.h b/external/badvpn_dns/dhcpclient/BDHCPClientCore.h
deleted file mode 100644
index 98cda36..0000000
--- a/external/badvpn_dns/dhcpclient/BDHCPClientCore.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * @file BDHCPClientCore.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * DHCP client, excluding system-dependent details.
- */
-
-#ifndef BADVPN_DHCPCLIENT_BDHCPCLIENTCORE_H
-#define BADVPN_DHCPCLIENT_BDHCPCLIENTCORE_H
-
-#include <stdint.h>
-#include <stddef.h>
-
-#include <system/BReactor.h>
-#include <base/DebugObject.h>
-#include <random/BRandom2.h>
-#include <flow/PacketPassInterface.h>
-#include <flow/PacketRecvInterface.h>
-
-#define BDHCPCLIENTCORE_EVENT_UP 1
-#define BDHCPCLIENTCORE_EVENT_DOWN 2
-
-#define BDHCPCLIENTCORE_MAX_DOMAIN_NAME_SERVERS 16
-
-typedef void (*BDHCPClientCore_func_getsendermac) (void *user, uint8_t *out_mac);
-typedef void (*BDHCPClientCore_handler) (void *user, int event);
-
-struct BDHCPClientCore_opts {
-    const char *hostname;
-    const char *vendorclassid;
-    const uint8_t *clientid;
-    size_t clientid_len;
-};
-
-typedef struct {
-    PacketPassInterface *send_if;
-    PacketRecvInterface *recv_if;
-    uint8_t client_mac_addr[6];
-    BReactor *reactor;
-    BRandom2 *random2;
-    void *user;
-    BDHCPClientCore_func_getsendermac func_getsendermac;
-    BDHCPClientCore_handler handler;
-    char *hostname;
-    char *vendorclassid;
-    uint8_t *clientid;
-    size_t clientid_len;
-    char *send_buf;
-    char *recv_buf;
-    int sending;
-    BTimer reset_timer;
-    BTimer request_timer;
-    BTimer renew_timer;
-    BTimer renew_request_timer;
-    BTimer lease_timer;
-    int state;
-    int request_count;
-    uint32_t xid;
-    int xid_reuse_counter;
-    struct {
-        uint32_t yiaddr;
-        uint32_t dhcp_server_identifier;
-    } offered;
-    struct {
-        uint32_t ip_address_lease_time;
-        uint32_t subnet_mask;
-        int have_router;
-        uint32_t router;
-        int domain_name_servers_count;
-        uint32_t domain_name_servers[BDHCPCLIENTCORE_MAX_DOMAIN_NAME_SERVERS];
-        uint8_t server_mac[6];
-    } acked;
-    DebugObject d_obj;
-} BDHCPClientCore;
-
-int BDHCPClientCore_Init (BDHCPClientCore *o, PacketPassInterface *send_if, PacketRecvInterface *recv_if,
-                          uint8_t *client_mac_addr, struct BDHCPClientCore_opts opts, BReactor *reactor,
-                          BRandom2 *random2, void *user,
-                          BDHCPClientCore_func_getsendermac func_getsendermac,
-                          BDHCPClientCore_handler handler);
-void BDHCPClientCore_Free (BDHCPClientCore *o);
-void BDHCPClientCore_GetClientIP (BDHCPClientCore *o, uint32_t *out_ip);
-void BDHCPClientCore_GetClientMask (BDHCPClientCore *o, uint32_t *out_mask);
-int BDHCPClientCore_GetRouter (BDHCPClientCore *o, uint32_t *out_router);
-int BDHCPClientCore_GetDNS (BDHCPClientCore *o, uint32_t *out_dns_servers, size_t max_dns_servers);
-void BDHCPClientCore_GetServerMAC (BDHCPClientCore *o, uint8_t *out_mac);
-
-#endif
diff --git a/external/badvpn_dns/dhcpclient/CMakeLists.txt b/external/badvpn_dns/dhcpclient/CMakeLists.txt
deleted file mode 100644
index 5fd1300..0000000
--- a/external/badvpn_dns/dhcpclient/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-badvpn_add_library(dhcpclientcore "system;flow;flowextra;badvpn_random" "" BDHCPClientCore.c)
-
-if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
-    set(DHCPCLIENT_SOURCES
-        BDHCPClient.c
-        DHCPIpUdpEncoder.c
-        DHCPIpUdpDecoder.c
-    )
-    badvpn_add_library(dhcpclient "system;flow;dhcpclientcore" "" "${DHCPCLIENT_SOURCES}")
-endif ()
diff --git a/external/badvpn_dns/dhcpclient/DHCPIpUdpDecoder.c b/external/badvpn_dns/dhcpclient/DHCPIpUdpDecoder.c
deleted file mode 100644
index 1d1c7a7..0000000
--- a/external/badvpn_dns/dhcpclient/DHCPIpUdpDecoder.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * @file DHCPIpUdpDecoder.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <limits.h>
-#include <string.h>
-
-#include <misc/ipv4_proto.h>
-#include <misc/udp_proto.h>
-#include <misc/byteorder.h>
-
-#include <dhcpclient/DHCPIpUdpDecoder.h>
-
-#define DHCP_SERVER_PORT 67
-#define DHCP_CLIENT_PORT 68
-
-#define IPUDP_HEADER_SIZE (sizeof(struct ipv4_header) + sizeof(struct udp_header))
-
-static void input_handler_send (DHCPIpUdpDecoder *o, uint8_t *data, int data_len)
-{
-    ASSERT(data_len >= 0)
-    DebugObject_Access(&o->d_obj);
-    
-    struct ipv4_header iph;
-    uint8_t *pl;
-    int pl_len;
-    
-    if (!ipv4_check(data, data_len, &iph, &pl, &pl_len)) {
-        goto fail;
-    }
-    
-    if (ntoh8(iph.protocol) != IPV4_PROTOCOL_UDP) {
-        goto fail;
-    }
-    
-    if (pl_len < sizeof(struct udp_header)) {
-        goto fail;
-    }
-    struct udp_header udph;
-    memcpy(&udph, pl, sizeof(udph));
-    
-    if (ntoh16(udph.source_port) != DHCP_SERVER_PORT) {
-        goto fail;
-    }
-    
-    if (ntoh16(udph.dest_port) != DHCP_CLIENT_PORT) {
-        goto fail;
-    }
-    
-    int udph_length = ntoh16(udph.length);
-    if (udph_length < sizeof(udph)) {
-        goto fail;
-    }
-    if (udph_length > data_len - (pl - data)) {
-        goto fail;
-    }
-    
-    if (ntoh16(udph.checksum) != 0) {
-        uint16_t checksum_in_packet = udph.checksum;
-        udph.checksum = 0;
-        uint16_t checksum_computed = udp_checksum(&udph, pl + sizeof(udph), udph_length - sizeof(udph), iph.source_address, iph.destination_address);
-        if (checksum_in_packet != checksum_computed) {
-            goto fail;
-        }
-    }
-    
-    // pass payload to output
-    PacketPassInterface_Sender_Send(o->output, pl + sizeof(udph), udph_length - sizeof(udph));
-    
-    return;
-    
-fail:
-    PacketPassInterface_Done(&o->input);
-}
-
-static void output_handler_done (DHCPIpUdpDecoder *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    PacketPassInterface_Done(&o->input);
-}
-
-void DHCPIpUdpDecoder_Init (DHCPIpUdpDecoder *o, PacketPassInterface *output, BPendingGroup *pg)
-{
-    ASSERT(PacketPassInterface_GetMTU(output) <= INT_MAX - IPUDP_HEADER_SIZE)
-    
-    // init arguments
-    o->output = output;
-    
-    // init output
-    PacketPassInterface_Sender_Init(o->output, (PacketPassInterface_handler_done)output_handler_done, o);
-    
-    // init input
-    PacketPassInterface_Init(&o->input, IPUDP_HEADER_SIZE + PacketPassInterface_GetMTU(o->output), (PacketPassInterface_handler_send)input_handler_send, o, pg);
-    
-    DebugObject_Init(&o->d_obj);
-}
-
-void DHCPIpUdpDecoder_Free (DHCPIpUdpDecoder *o)
-{
-    DebugObject_Free(&o->d_obj);
-    
-    // free input
-    PacketPassInterface_Free(&o->input);
-}
-
-PacketPassInterface * DHCPIpUdpDecoder_GetInput (DHCPIpUdpDecoder *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->input;
-}
diff --git a/external/badvpn_dns/dhcpclient/DHCPIpUdpDecoder.h b/external/badvpn_dns/dhcpclient/DHCPIpUdpDecoder.h
deleted file mode 100644
index ce92138..0000000
--- a/external/badvpn_dns/dhcpclient/DHCPIpUdpDecoder.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * @file DHCPIpUdpDecoder.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BADVPN_DHCPCLIENT_DHCPIPUDPDECODER_H
-#define BADVPN_DHCPCLIENT_DHCPIPUDPDECODER_H
-
-#include <stdint.h>
-
-#include <base/DebugObject.h>
-#include <flow/PacketPassInterface.h>
-
-typedef struct {
-    PacketPassInterface *output;
-    PacketPassInterface input;
-    uint8_t *data;
-    DebugObject d_obj;
-} DHCPIpUdpDecoder;
-
-void DHCPIpUdpDecoder_Init (DHCPIpUdpDecoder *o, PacketPassInterface *output, BPendingGroup *pg);
-void DHCPIpUdpDecoder_Free (DHCPIpUdpDecoder *o);
-PacketPassInterface * DHCPIpUdpDecoder_GetInput (DHCPIpUdpDecoder *o);
-
-#endif
diff --git a/external/badvpn_dns/dhcpclient/DHCPIpUdpEncoder.c b/external/badvpn_dns/dhcpclient/DHCPIpUdpEncoder.c
deleted file mode 100644
index da6645c..0000000
--- a/external/badvpn_dns/dhcpclient/DHCPIpUdpEncoder.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * @file DHCPIpUdpEncoder.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <limits.h>
-#include <string.h>
-#include <stddef.h>
-
-#include <misc/ipv4_proto.h>
-#include <misc/udp_proto.h>
-#include <misc/byteorder.h>
-
-#include <dhcpclient/DHCPIpUdpEncoder.h>
-
-#define DHCP_SERVER_PORT 67
-#define DHCP_CLIENT_PORT 68
-
-#define IPUDP_HEADER_SIZE (sizeof(struct ipv4_header) + sizeof(struct udp_header))
-
-static void output_handler_recv (DHCPIpUdpEncoder *o, uint8_t *data)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    // remember output packet
-    o->data = data;
-    
-    // receive payload
-    PacketRecvInterface_Receiver_Recv(o->input, o->data + IPUDP_HEADER_SIZE);
-}
-
-static void input_handler_done (DHCPIpUdpEncoder *o, int data_len)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    // build IP header
-    struct ipv4_header iph;
-    iph.version4_ihl4 = IPV4_MAKE_VERSION_IHL(sizeof(iph));
-    iph.ds = hton8(0);
-    iph.total_length = hton16(IPUDP_HEADER_SIZE + data_len);
-    iph.identification = hton16(0);
-    iph.flags3_fragmentoffset13 = hton16(0);
-    iph.ttl = hton8(64);
-    iph.protocol = hton8(IPV4_PROTOCOL_UDP);
-    iph.checksum = hton16(0);
-    iph.source_address = hton32(0x00000000);
-    iph.destination_address = hton32(0xFFFFFFFF);
-    iph.checksum = ipv4_checksum(&iph, NULL, 0);
-    
-    // write UDP header
-    struct udp_header udph;
-    udph.source_port = hton16(DHCP_CLIENT_PORT);
-    udph.dest_port = hton16(DHCP_SERVER_PORT);
-    udph.length = hton16(sizeof(udph) + data_len);
-    udph.checksum = hton16(0);
-    udph.checksum = udp_checksum(&udph, o->data + IPUDP_HEADER_SIZE, data_len, iph.source_address, iph.destination_address);
-    
-    // write header
-    memcpy(o->data, &iph, sizeof(iph));
-    memcpy(o->data + sizeof(iph), &udph, sizeof(udph));
-    
-    // finish packet
-    PacketRecvInterface_Done(&o->output, IPUDP_HEADER_SIZE + data_len);
-}
-
-void DHCPIpUdpEncoder_Init (DHCPIpUdpEncoder *o, PacketRecvInterface *input, BPendingGroup *pg)
-{
-    ASSERT(PacketRecvInterface_GetMTU(input) <= INT_MAX - IPUDP_HEADER_SIZE)
-    
-    // init arguments
-    o->input = input;
-    
-    // init input
-    PacketRecvInterface_Receiver_Init(o->input, (PacketRecvInterface_handler_done)input_handler_done, o);
-    
-    // init output
-    PacketRecvInterface_Init(&o->output, IPUDP_HEADER_SIZE + PacketRecvInterface_GetMTU(o->input), (PacketRecvInterface_handler_recv)output_handler_recv, o, pg);
-    
-    DebugObject_Init(&o->d_obj);
-}
-
-void DHCPIpUdpEncoder_Free (DHCPIpUdpEncoder *o)
-{
-    DebugObject_Free(&o->d_obj);
-    
-    // free output
-    PacketRecvInterface_Free(&o->output);
-}
-
-PacketRecvInterface * DHCPIpUdpEncoder_GetOutput (DHCPIpUdpEncoder *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->output;
-}
diff --git a/external/badvpn_dns/dhcpclient/DHCPIpUdpEncoder.h b/external/badvpn_dns/dhcpclient/DHCPIpUdpEncoder.h
deleted file mode 100644
index d3e0ac0..0000000
--- a/external/badvpn_dns/dhcpclient/DHCPIpUdpEncoder.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * @file DHCPIpUdpEncoder.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BADVPN_DHCPCLIENT_DHCPIPUDPENCODER_H
-#define BADVPN_DHCPCLIENT_DHCPIPUDPENCODER_H
-
-#include <stdint.h>
-
-#include <base/DebugObject.h>
-#include <flow/PacketRecvInterface.h>
-
-typedef struct {
-    PacketRecvInterface *input;
-    PacketRecvInterface output;
-    uint8_t *data;
-    DebugObject d_obj;
-} DHCPIpUdpEncoder;
-
-void DHCPIpUdpEncoder_Init (DHCPIpUdpEncoder *o, PacketRecvInterface *input, BPendingGroup *pg);
-void DHCPIpUdpEncoder_Free (DHCPIpUdpEncoder *o);
-PacketRecvInterface * DHCPIpUdpEncoder_GetOutput (DHCPIpUdpEncoder *o);
-
-#endif
diff --git a/external/badvpn_dns/dostest/CMakeLists.txt b/external/badvpn_dns/dostest/CMakeLists.txt
deleted file mode 100644
index 8d3b742..0000000
--- a/external/badvpn_dns/dostest/CMakeLists.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-add_executable(dostest-server
-    dostest-server.c
-    StreamBuffer.c
-)
-target_link_libraries(dostest-server base system)
-
-add_executable(dostest-attacker
-    dostest-attacker.c
-)
-target_link_libraries(dostest-attacker base system)
diff --git a/external/badvpn_dns/dostest/StreamBuffer.c b/external/badvpn_dns/dostest/StreamBuffer.c
deleted file mode 100644
index d439127..0000000
--- a/external/badvpn_dns/dostest/StreamBuffer.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/**
- * @file StreamBuffer.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <misc/balloc.h>
-#include <misc/minmax.h>
-
-#include "StreamBuffer.h"
-
-// called when receive operation is complete
-static void input_handler_done (void *vo, int data_len)
-{
-    StreamBuffer *o = (StreamBuffer *)vo;
-    ASSERT(data_len > 0)
-    ASSERT(data_len <= o->buf_size - (o->buf_start + o->buf_used))
-    
-    // remember if buffer was empty
-    int was_empty = (o->buf_used == 0);
-    
-    // increment buf_used by the amount that was received
-    o->buf_used += data_len;
-    
-    // start another receive operation unless buffer is full
-    if (o->buf_used < o->buf_size - o->buf_start) {
-        int end = o->buf_start + o->buf_used;
-        StreamRecvInterface_Receiver_Recv(o->input, o->buf + end, o->buf_size - end);
-    }
-    else if (o->buf_used < o->buf_size) {
-        // wrap around
-        StreamRecvInterface_Receiver_Recv(o->input, o->buf, o->buf_start);
-    }
-    
-    // if buffer was empty before, start send operation
-    if (was_empty) {
-        StreamPassInterface_Sender_Send(o->output, o->buf + o->buf_start, o->buf_used);
-    }
-}
-
-// called when send operation is complete
-static void output_handler_done (void *vo, int data_len)
-{
-    StreamBuffer *o = (StreamBuffer *)vo;
-    ASSERT(data_len > 0)
-    ASSERT(data_len <= o->buf_used)
-    ASSERT(data_len <= o->buf_size - o->buf_start)
-    
-    // remember if buffer was full
-    int was_full = (o->buf_used == o->buf_size);
-    
-    // increment buf_start and decrement buf_used by the
-    // amount that was sent
-    o->buf_start += data_len;
-    o->buf_used -= data_len;
-    
-    // wrap around buf_start
-    if (o->buf_start == o->buf_size) {
-        o->buf_start = 0;
-    }
-    
-    // start receive operation if buffer was full
-    if (was_full) {
-        int end;
-        int avail;
-        if (o->buf_used >= o->buf_size - o->buf_start) {
-            end = o->buf_used - (o->buf_size - o->buf_start);
-            avail = o->buf_start - end;
-        } else {
-            end = o->buf_start + o->buf_used;
-            avail = o->buf_size - end;
-        }
-        StreamRecvInterface_Receiver_Recv(o->input, o->buf + end, avail);
-    }
-    
-    // start another receive send unless buffer is empty
-    if (o->buf_used > 0) {
-        int to_send = bmin_int(o->buf_used, o->buf_size - o->buf_start);
-        StreamPassInterface_Sender_Send(o->output, o->buf + o->buf_start, to_send);
-    }
-}
-
-int StreamBuffer_Init (StreamBuffer *o, int buf_size, StreamRecvInterface *input, StreamPassInterface *output)
-{
-    ASSERT(buf_size > 0)
-    ASSERT(input)
-    ASSERT(output)
-    
-    // remember arguments
-    o->buf_size = buf_size;
-    o->input = input;
-    o->output = output;
-    
-    // allocate buffer memory
-    o->buf = (uint8_t *)BAllocSize(bsize_fromint(o->buf_size));
-    if (!o->buf) {
-        goto fail0;
-    }
-    
-    // set initial buffer state
-    o->buf_start = 0;
-    o->buf_used = 0;
-    
-    // set receive and send done callbacks
-    StreamRecvInterface_Receiver_Init(o->input, input_handler_done, o);
-    StreamPassInterface_Sender_Init(o->output, output_handler_done, o);
-    
-    // start receive operation
-    StreamRecvInterface_Receiver_Recv(o->input, o->buf, o->buf_size);
-    
-    DebugObject_Init(&o->d_obj);
-    return 1;
-    
-fail0:
-    return 0;
-}
-
-void StreamBuffer_Free (StreamBuffer *o)
-{
-    DebugObject_Free(&o->d_obj);
-    
-    // free buffer memory
-    BFree(o->buf);
-}
diff --git a/external/badvpn_dns/dostest/StreamBuffer.h b/external/badvpn_dns/dostest/StreamBuffer.h
deleted file mode 100644
index dd441f5..0000000
--- a/external/badvpn_dns/dostest/StreamBuffer.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * @file StreamBuffer.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BADVPN_STREAMBUFFER_H
-#define BADVPN_STREAMBUFFER_H
-
-#include <misc/debug.h>
-#include <base/DebugObject.h>
-#include <flow/StreamRecvInterface.h>
-#include <flow/StreamPassInterface.h>
-
-/**
- * Buffer object which reads data from a \link StreamRecvInterface and writes
- * it to a \link StreamPassInterface.
- */
-typedef struct {
-    int buf_size;
-    StreamRecvInterface *input;
-    StreamPassInterface *output;
-    uint8_t *buf;
-    int buf_start;
-    int buf_used;
-    DebugObject d_obj;
-} StreamBuffer;
-
-/**
- * Initializes the buffer object.
- * 
- * @param o object to initialize
- * @param buf_size size of the buffer. Must be >0.
- * @param input input interface
- * @param outout output interface
- * @return 1 on success, 0 on failure
- */
-int StreamBuffer_Init (StreamBuffer *o, int buf_size, StreamRecvInterface *input, StreamPassInterface *output) WARN_UNUSED;
-
-/**
- * Frees the buffer object.
- * 
- * @param o object to free
- */
-void StreamBuffer_Free (StreamBuffer *o);
-
-#endif
diff --git a/external/badvpn_dns/dostest/dostest-attacker.c b/external/badvpn_dns/dostest/dostest-attacker.c
deleted file mode 100644
index 723dadd..0000000
--- a/external/badvpn_dns/dostest/dostest-attacker.c
+++ /dev/null
@@ -1,512 +0,0 @@
-/**
- * @file dostest-attacker.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-
-#include <misc/debug.h>
-#include <misc/version.h>
-#include <misc/offset.h>
-#include <misc/open_standard_streams.h>
-#include <misc/balloc.h>
-#include <misc/loglevel.h>
-#include <misc/minmax.h>
-#include <structure/LinkedList1.h>
-#include <base/BLog.h>
-#include <system/BAddr.h>
-#include <system/BReactor.h>
-#include <system/BNetwork.h>
-#include <system/BConnection.h>
-#include <system/BSignal.h>
-
-#include <generated/blog_channel_dostest_attacker.h>
-
-#define PROGRAM_NAME "dostest-attacker"
-
-// connection structure
-struct connection {
-    int connected;
-    BConnector connector;
-    BConnection con;
-    StreamRecvInterface *recv_if;
-    uint8_t buf[512];
-    LinkedList1Node connections_list_node;
-};
-
-// command-line options
-static struct {
-    int help;
-    int version;
-    char *connect_addr;
-    int max_connections;
-    int max_connecting;
-    int loglevel;
-    int loglevels[BLOG_NUM_CHANNELS];
-} options;
-
-// connect address
-static BAddr connect_addr;
-
-// reactor
-static BReactor reactor;
-
-// connections
-static LinkedList1 connections_list;
-static int num_connections;
-static int num_connecting;
-
-// timer for scheduling creation of more connections
-static BTimer make_connections_timer;
-
-static void print_help (const char *name);
-static void print_version (void);
-static int parse_arguments (int argc, char *argv[]);
-static int process_arguments (void);
-static void signal_handler (void *unused);
-static int connection_new (void);
-static void connection_free (struct connection *conn);
-static void connection_logfunc (struct connection *conn);
-static void connection_log (struct connection *conn, int level, const char *fmt, ...);
-static void connection_connector_handler (struct connection *conn, int is_error);
-static void connection_connection_handler (struct connection *conn, int event);
-static void connection_recv_handler_done (struct connection *conn, int data_len);
-static void make_connections_timer_handler (void *unused);
-
-int main (int argc, char **argv)
-{
-    if (argc <= 0) {
-        return 1;
-    }
-    
-    // open standard streams
-    open_standard_streams();
-    
-    // parse command-line arguments
-    if (!parse_arguments(argc, argv)) {
-        fprintf(stderr, "Failed to parse arguments\n");
-        print_help(argv[0]);
-        goto fail0;
-    }
-    
-    // handle --help and --version
-    if (options.help) {
-        print_version();
-        print_help(argv[0]);
-        return 0;
-    }
-    if (options.version) {
-        print_version();
-        return 0;
-    }
-    
-    // init loger
-    BLog_InitStderr();
-    
-    // configure logger channels
-    for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
-        if (options.loglevels[i] >= 0) {
-            BLog_SetChannelLoglevel(i, options.loglevels[i]);
-        }
-        else if (options.loglevel >= 0) {
-            BLog_SetChannelLoglevel(i, options.loglevel);
-        }
-    }
-    
-    BLog(BLOG_NOTICE, "initializing "GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION);
-    
-    // initialize network
-    if (!BNetwork_GlobalInit()) {
-        BLog(BLOG_ERROR, "BNetwork_GlobalInit failed");
-        goto fail1;
-    }
-    
-    // process arguments
-    if (!process_arguments()) {
-        BLog(BLOG_ERROR, "Failed to process arguments");
-        goto fail1;
-    }
-    
-    // init time
-    BTime_Init();
-    
-    // init reactor
-    if (!BReactor_Init(&reactor)) {
-        BLog(BLOG_ERROR, "BReactor_Init failed");
-        goto fail1;
-    }
-    
-    // setup signal handler
-    if (!BSignal_Init(&reactor, signal_handler, NULL)) {
-        BLog(BLOG_ERROR, "BSignal_Init failed");
-        goto fail2;
-    }
-    
-    // init connections list
-    LinkedList1_Init(&connections_list);
-    num_connections = 0;
-    num_connecting = 0;
-    
-    // init make connections timer
-    BTimer_Init(&make_connections_timer, 0, make_connections_timer_handler, NULL);
-    BReactor_SetTimer(&reactor, &make_connections_timer);
-    
-    // enter event loop
-    BLog(BLOG_NOTICE, "entering event loop");
-    BReactor_Exec(&reactor);
-    
-    // free connections
-    while (!LinkedList1_IsEmpty(&connections_list)) {
-        struct connection *conn = UPPER_OBJECT(LinkedList1_GetFirst(&connections_list), struct connection, connections_list_node);
-        connection_free(conn);
-    }
-    // free make connections timer
-    BReactor_RemoveTimer(&reactor, &make_connections_timer);
-    // free signal
-    BSignal_Finish();
-fail2:
-    // free reactor
-    BReactor_Free(&reactor);
-fail1:
-    // free logger
-    BLog(BLOG_NOTICE, "exiting");
-    BLog_Free();
-fail0:
-    // finish debug objects
-    DebugObjectGlobal_Finish();
-    
-    return 1;
-}
-
-void print_help (const char *name)
-{
-    printf(
-        "Usage:\n"
-        "    %s\n"
-        "        [--help]\n"
-        "        [--version]\n"
-        "        --connect-addr <addr>\n"
-        "        --max-connections <number>\n"
-        "        --max-connecting <number>\n"
-        "        [--loglevel <0-5/none/error/warning/notice/info/debug>]\n"
-        "        [--channel-loglevel <channel-name> <0-5/none/error/warning/notice/info/debug>] ...\n"
-        "Address format is a.b.c.d:port (IPv4) or [addr]:port (IPv6).\n",
-        name
-    );
-}
-
-void print_version (void)
-{
-    printf(GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION"\n"GLOBAL_COPYRIGHT_NOTICE"\n");
-}
-
-int parse_arguments (int argc, char *argv[])
-{
-    options.help = 0;
-    options.version = 0;
-    options.connect_addr = NULL;
-    options.max_connections = -1;
-    options.max_connecting = -1;
-    options.loglevel = -1;
-    for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
-        options.loglevels[i] = -1;
-    }
-    
-    int i;
-    for (i = 1; i < argc; i++) {
-        char *arg = argv[i];
-        if (!strcmp(arg, "--help")) {
-            options.help = 1;
-        }
-        else if (!strcmp(arg, "--version")) {
-            options.version = 1;
-        }
-        else if (!strcmp(arg, "--connect-addr")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.connect_addr = argv[i + 1];
-            i++;
-        }
-        else if (!strcmp(arg, "--max-connections")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.max_connections = atoi(argv[i + 1])) <= 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--max-connecting")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.max_connecting = atoi(argv[i + 1])) <= 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--loglevel")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.loglevel = parse_loglevel(argv[i + 1])) < 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--channel-loglevel")) {
-            if (2 >= argc - i) {
-                fprintf(stderr, "%s: requires two arguments\n", arg);
-                return 0;
-            }
-            int channel = BLogGlobal_GetChannelByName(argv[i + 1]);
-            if (channel < 0) {
-                fprintf(stderr, "%s: wrong channel argument\n", arg);
-                return 0;
-            }
-            int loglevel = parse_loglevel(argv[i + 2]);
-            if (loglevel < 0) {
-                fprintf(stderr, "%s: wrong loglevel argument\n", arg);
-                return 0;
-            }
-            options.loglevels[channel] = loglevel;
-            i += 2;
-        }
-        else {
-            fprintf(stderr, "unknown option: %s\n", arg);
-            return 0;
-        }
-    }
-    
-    if (options.help || options.version) {
-        return 1;
-    }
-    
-    if (!options.connect_addr) {
-        fprintf(stderr, "--connect-addr missing\n");
-        return 0;
-    }
-    
-    if (options.max_connections == -1) {
-        fprintf(stderr, "--max-connections missing\n");
-        return 0;
-    }
-    
-    if (options.max_connecting == -1) {
-        fprintf(stderr, "--max-connecting missing\n");
-        return 0;
-    }
-    
-    return 1;
-}
-
-int process_arguments (void)
-{
-    // resolve listen address
-    if (!BAddr_Parse(&connect_addr, options.connect_addr, NULL, 0)) {
-        BLog(BLOG_ERROR, "connect addr: BAddr_Parse failed");
-        return 0;
-    }
-    
-    return 1;
-}
-
-void signal_handler (void *unused)
-{
-    BLog(BLOG_NOTICE, "termination requested");
-    
-    // exit event loop
-    BReactor_Quit(&reactor, 1);
-}
-
-int connection_new (void)
-{
-    // allocate structure
-    struct connection *conn = (struct connection *)malloc(sizeof(*conn));
-    if (!conn) {
-        BLog(BLOG_ERROR, "malloc failed");
-        goto fail0;
-    }
-    
-    // set not connected
-    conn->connected = 0;
-    
-    // init connector
-    if (!BConnector_Init(&conn->connector, connect_addr, &reactor, conn, (BConnector_handler)connection_connector_handler)) {
-        BLog(BLOG_ERROR, "BConnector_Init failed");
-        goto fail1;
-    }
-    
-    // add to connections list
-    LinkedList1_Append(&connections_list, &conn->connections_list_node);
-    num_connections++;
-    num_connecting++;
-    
-    return 1;
-    
-fail1:
-    free(conn);
-fail0:
-    return 0;
-}
-
-void connection_free (struct connection *conn)
-{
-    // remove from connections list
-    LinkedList1_Remove(&connections_list, &conn->connections_list_node);
-    num_connections--;
-    if (!conn->connected) {
-        num_connecting--;
-    }
-    
-    if (conn->connected) {
-        // free receive interface
-        BConnection_RecvAsync_Free(&conn->con);
-        
-        // free connection
-        BConnection_Free(&conn->con);
-    }
-    
-    // free connector
-    BConnector_Free(&conn->connector);
-    
-    // free structure
-    free(conn);
-}
-
-void connection_logfunc (struct connection *conn)
-{
-    BLog_Append("%d connection (%p): ", num_connecting, (void *)conn);
-}
-
-void connection_log (struct connection *conn, int level, const char *fmt, ...)
-{
-    va_list vl;
-    va_start(vl, fmt);
-    BLog_LogViaFuncVarArg((BLog_logfunc)connection_logfunc, conn, BLOG_CURRENT_CHANNEL, level, fmt, vl);
-    va_end(vl);
-}
-
-void connection_connector_handler (struct connection *conn, int is_error)
-{
-    ASSERT(!conn->connected)
-    
-    // check for connection error
-    if (is_error) {
-        connection_log(conn, BLOG_INFO, "failed to connect");
-        goto fail0;
-    }
-    
-    // init connection from connector
-    if (!BConnection_Init(&conn->con, BConnection_source_connector(&conn->connector), &reactor, conn, (BConnection_handler)connection_connection_handler)) {
-        connection_log(conn, BLOG_INFO, "BConnection_Init failed");
-        goto fail0;
-    }
-    
-    // init receive interface
-    BConnection_RecvAsync_Init(&conn->con);
-    conn->recv_if = BConnection_RecvAsync_GetIf(&conn->con);
-    StreamRecvInterface_Receiver_Init(conn->recv_if, (StreamRecvInterface_handler_done)connection_recv_handler_done, conn);
-    
-    // start receiving
-    StreamRecvInterface_Receiver_Recv(conn->recv_if, conn->buf, sizeof(conn->buf));
-    
-    // no longer connecting
-    conn->connected = 1;
-    num_connecting--;
-    
-    connection_log(conn, BLOG_INFO, "connected");
-    
-    // schedule making connections (because of connecting limit)
-    BReactor_SetTimer(&reactor, &make_connections_timer);
-    return;
-    
-fail0:
-    // free connection
-    connection_free(conn);
-    
-    // schedule making connections
-    BReactor_SetTimer(&reactor, &make_connections_timer);
-}
-
-void connection_connection_handler (struct connection *conn, int event)
-{
-    ASSERT(conn->connected)
-    
-    if (event == BCONNECTION_EVENT_RECVCLOSED) {
-        connection_log(conn, BLOG_INFO, "connection closed");
-    } else {
-        connection_log(conn, BLOG_INFO, "connection error");
-    }
-    
-    // free connection
-    connection_free(conn);
-    
-    // schedule making connections
-    BReactor_SetTimer(&reactor, &make_connections_timer);
-}
-
-void connection_recv_handler_done (struct connection *conn, int data_len)
-{
-    ASSERT(conn->connected)
-    
-    // receive more
-    StreamRecvInterface_Receiver_Recv(conn->recv_if, conn->buf, sizeof(conn->buf));
-    
-    connection_log(conn, BLOG_INFO, "received %d bytes", data_len);
-}
-
-void make_connections_timer_handler (void *unused)
-{
-    int make_num = bmin_int(options.max_connections - num_connections, options.max_connecting - num_connecting);
-    
-    if (make_num <= 0) {
-        return;
-    }
-    
-    BLog(BLOG_INFO, "making %d connections", make_num);
-    
-    for (int i = 0; i < make_num; i++) {
-        if (!connection_new()) {
-            // can happen if fd limit is reached
-            BLog(BLOG_ERROR, "failed to make connection, waiting");
-            BReactor_SetTimerAfter(&reactor, &make_connections_timer, 10);
-            return;
-        }
-    }
-}
diff --git a/external/badvpn_dns/dostest/dostest-server.c b/external/badvpn_dns/dostest/dostest-server.c
deleted file mode 100644
index 7447591..0000000
--- a/external/badvpn_dns/dostest/dostest-server.c
+++ /dev/null
@@ -1,567 +0,0 @@
-/**
- * @file dostest-server.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-
-#ifdef BADVPN_LINUX
-#include <sys/types.h>
-#include <sys/socket.h>
-#endif
-
-#include <misc/debug.h>
-#include <misc/version.h>
-#include <misc/offset.h>
-#include <misc/open_standard_streams.h>
-#include <misc/balloc.h>
-#include <misc/loglevel.h>
-#include <structure/LinkedList1.h>
-#include <base/BLog.h>
-#include <system/BAddr.h>
-#include <system/BReactor.h>
-#include <system/BNetwork.h>
-#include <system/BConnection.h>
-#include <system/BSignal.h>
-#include "StreamBuffer.h"
-
-#include <generated/blog_channel_dostest_server.h>
-
-#define PROGRAM_NAME "dostest-server"
-
-#ifdef BADVPN_LINUX
-#ifndef SO_DOSDEF_PREPARE
-#define SO_DOSDEF_PREPARE 48
-#endif
-#ifndef SO_DOSDEF_ACTIVATE
-#define SO_DOSDEF_ACTIVATE 49
-#endif
-#endif
-
-#define BUF_SIZE 1024
-
-// client structure
-struct client {
-    BConnection con;
-    BAddr addr;
-    StreamBuffer buf;
-    BTimer disconnect_timer;
-    LinkedList1Node clients_list_node;
-};
-
-// command-line options
-static struct {
-    int help;
-    int version;
-    char *listen_addr;
-    int max_clients;
-    int disconnect_time;
-    int defense_prepare_clients;
-    int defense_activate_clients;
-    int loglevel;
-    int loglevels[BLOG_NUM_CHANNELS];
-} options;
-
-// listen address
-static BAddr listen_addr;
-
-// reactor
-static BReactor ss;
-
-// listener
-static BListener listener;
-
-// clients
-static LinkedList1 clients_list;
-static int num_clients;
-
-// defense status
-static int defense_prepare;
-static int defense_activate;
-
-static void print_help (const char *name);
-static void print_version (void);
-static int parse_arguments (int argc, char *argv[]);
-static int process_arguments (void);
-static void signal_handler (void *unused);
-static void listener_handler (void *unused);
-static void client_free (struct client *client);
-static void client_logfunc (struct client *client);
-static void client_log (struct client *client, int level, const char *fmt, ...);
-static void client_disconnect_timer_handler (struct client *client);
-static void client_connection_handler (struct client *client, int event);
-static void update_defense (void);
-
-int main (int argc, char **argv)
-{
-    if (argc <= 0) {
-        return 1;
-    }
-    
-    // open standard streams
-    open_standard_streams();
-    
-    // parse command-line arguments
-    if (!parse_arguments(argc, argv)) {
-        fprintf(stderr, "Failed to parse arguments\n");
-        print_help(argv[0]);
-        goto fail0;
-    }
-    
-    // handle --help and --version
-    if (options.help) {
-        print_version();
-        print_help(argv[0]);
-        return 0;
-    }
-    if (options.version) {
-        print_version();
-        return 0;
-    }
-    
-    // init loger
-    BLog_InitStderr();
-    
-    // configure logger channels
-    for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
-        if (options.loglevels[i] >= 0) {
-            BLog_SetChannelLoglevel(i, options.loglevels[i]);
-        }
-        else if (options.loglevel >= 0) {
-            BLog_SetChannelLoglevel(i, options.loglevel);
-        }
-    }
-    
-    BLog(BLOG_NOTICE, "initializing "GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION);
-    
-    // initialize network
-    if (!BNetwork_GlobalInit()) {
-        BLog(BLOG_ERROR, "BNetwork_GlobalInit failed");
-        goto fail1;
-    }
-    
-    // process arguments
-    if (!process_arguments()) {
-        BLog(BLOG_ERROR, "Failed to process arguments");
-        goto fail1;
-    }
-    
-    // init time
-    BTime_Init();
-    
-    // init reactor
-    if (!BReactor_Init(&ss)) {
-        BLog(BLOG_ERROR, "BReactor_Init failed");
-        goto fail1;
-    }
-    
-    // setup signal handler
-    if (!BSignal_Init(&ss, signal_handler, NULL)) {
-        BLog(BLOG_ERROR, "BSignal_Init failed");
-        goto fail2;
-    }
-    
-    // initialize listener
-    if (!BListener_Init(&listener, listen_addr, &ss, NULL, listener_handler)) {
-        BLog(BLOG_ERROR, "Listener_Init failed");
-        goto fail3;
-    }
-    
-    // init clients list
-    LinkedList1_Init(&clients_list);
-    num_clients = 0;
-    
-    // clear defense state
-    defense_prepare = 0;
-    defense_activate = 0;
-    
-    // update defense
-    update_defense();
-    
-    // enter event loop
-    BLog(BLOG_NOTICE, "entering event loop");
-    BReactor_Exec(&ss);
-    
-    // free clients
-    while (!LinkedList1_IsEmpty(&clients_list)) {
-        struct client *client = UPPER_OBJECT(LinkedList1_GetFirst(&clients_list), struct client, clients_list_node);
-        client_free(client);
-    }
-    // free listener
-    BListener_Free(&listener);
-fail3:
-    // free signal
-    BSignal_Finish();
-fail2:
-    // free reactor
-    BReactor_Free(&ss);
-fail1:
-    // free logger
-    BLog(BLOG_NOTICE, "exiting");
-    BLog_Free();
-fail0:
-    // finish debug objects
-    DebugObjectGlobal_Finish();
-    
-    return 1;
-}
-
-void print_help (const char *name)
-{
-    printf(
-        "Usage:\n"
-        "    %s\n"
-        "        [--help]\n"
-        "        [--version]\n"
-        "        --listen-addr <addr>\n"
-        "        --max-clients <number>\n"
-        "        --disconnect-time <milliseconds>\n"
-        "        [--defense-prepare-clients <number>]\n"
-        "        [--defense-activate-clients <number>]\n"
-        "        [--loglevel <0-5/none/error/warning/notice/info/debug>]\n"
-        "        [--channel-loglevel <channel-name> <0-5/none/error/warning/notice/info/debug>] ...\n"
-        "Address format is a.b.c.d:port (IPv4) or [addr]:port (IPv6).\n",
-        name
-    );
-}
-
-void print_version (void)
-{
-    printf(GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION"\n"GLOBAL_COPYRIGHT_NOTICE"\n");
-}
-
-int parse_arguments (int argc, char *argv[])
-{
-    options.help = 0;
-    options.version = 0;
-    options.listen_addr = NULL;
-    options.max_clients = -1;
-    options.disconnect_time = -1;
-    options.defense_prepare_clients = -1;
-    options.defense_activate_clients = -1;
-    options.loglevel = -1;
-    for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
-        options.loglevels[i] = -1;
-    }
-    
-    int i;
-    for (i = 1; i < argc; i++) {
-        char *arg = argv[i];
-        if (!strcmp(arg, "--help")) {
-            options.help = 1;
-        }
-        else if (!strcmp(arg, "--version")) {
-            options.version = 1;
-        }
-        else if (!strcmp(arg, "--listen-addr")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.listen_addr = argv[i + 1];
-            i++;
-        }
-        else if (!strcmp(arg, "--max-clients")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.max_clients = atoi(argv[i + 1])) <= 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--disconnect-time")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.disconnect_time = atoi(argv[i + 1])) <= 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--defense-prepare-clients")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.defense_prepare_clients = atoi(argv[i + 1])) <= 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--defense-activate-clients")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.defense_activate_clients = atoi(argv[i + 1])) <= 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--loglevel")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.loglevel = parse_loglevel(argv[i + 1])) < 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--channel-loglevel")) {
-            if (2 >= argc - i) {
-                fprintf(stderr, "%s: requires two arguments\n", arg);
-                return 0;
-            }
-            int channel = BLogGlobal_GetChannelByName(argv[i + 1]);
-            if (channel < 0) {
-                fprintf(stderr, "%s: wrong channel argument\n", arg);
-                return 0;
-            }
-            int loglevel = parse_loglevel(argv[i + 2]);
-            if (loglevel < 0) {
-                fprintf(stderr, "%s: wrong loglevel argument\n", arg);
-                return 0;
-            }
-            options.loglevels[channel] = loglevel;
-            i += 2;
-        }
-        else {
-            fprintf(stderr, "unknown option: %s\n", arg);
-            return 0;
-        }
-    }
-    
-    if (options.help || options.version) {
-        return 1;
-    }
-    
-    if (!options.listen_addr) {
-        fprintf(stderr, "--listen-addr missing\n");
-        return 0;
-    }
-    
-    if (options.max_clients == -1) {
-        fprintf(stderr, "--max-clients missing\n");
-        return 0;
-    }
-    
-    if (options.disconnect_time == -1) {
-        fprintf(stderr, "--disconnect-time missing\n");
-        return 0;
-    }
-    
-    return 1;
-}
-
-int process_arguments (void)
-{
-    // resolve listen address
-    if (!BAddr_Parse(&listen_addr, options.listen_addr, NULL, 0)) {
-        BLog(BLOG_ERROR, "listen addr: BAddr_Parse failed");
-        return 0;
-    }
-    
-    return 1;
-}
-
-void signal_handler (void *unused)
-{
-    BLog(BLOG_NOTICE, "termination requested");
-    
-    // exit event loop
-    BReactor_Quit(&ss, 1);
-}
-
-void listener_handler (void *unused)
-{
-    if (num_clients == options.max_clients) {
-        BLog(BLOG_ERROR, "maximum number of clients reached");
-        goto fail0;
-    }
-    
-    // allocate structure
-    struct client *client = (struct client *)malloc(sizeof(*client));
-    if (!client) {
-        BLog(BLOG_ERROR, "malloc failed");
-        goto fail0;
-    }
-    
-    // accept client
-    if (!BConnection_Init(&client->con, BConnection_source_listener(&listener, &client->addr), &ss, client, (BConnection_handler)client_connection_handler)) {
-        BLog(BLOG_ERROR, "BConnection_Init failed");
-        goto fail1;
-    }
-    
-    // init connection interfaces
-    BConnection_RecvAsync_Init(&client->con);
-    BConnection_SendAsync_Init(&client->con);
-    StreamRecvInterface *recv_if = BConnection_RecvAsync_GetIf(&client->con);
-    StreamPassInterface *send_if = BConnection_SendAsync_GetIf(&client->con);
-    
-    // init stream buffer (to loop received data back to the client)
-    if (!StreamBuffer_Init(&client->buf, BUF_SIZE, recv_if, send_if)) {
-        BLog(BLOG_ERROR, "StreamBuffer_Init failed");
-        goto fail2;
-    }
-    
-    // init disconnect timer
-    BTimer_Init(&client->disconnect_timer, options.disconnect_time, (BTimer_handler)client_disconnect_timer_handler, client);
-    BReactor_SetTimer(&ss, &client->disconnect_timer);
-    
-    // insert to clients list
-    LinkedList1_Append(&clients_list, &client->clients_list_node);
-    num_clients++;
-    
-    client_log(client, BLOG_INFO, "connected");
-    BLog(BLOG_NOTICE, "%d clients", num_clients);
-    
-    // update defense
-    update_defense();
-    return;
-    
-fail2:
-    BConnection_SendAsync_Free(&client->con);
-    BConnection_RecvAsync_Free(&client->con);
-    BConnection_Free(&client->con);
-fail1:
-    free(client);
-fail0:
-    return;
-}
-
-void client_free (struct client *client)
-{
-    // remove from clients list
-    LinkedList1_Remove(&clients_list, &client->clients_list_node);
-    num_clients--;
-    
-    // free disconnect timer
-    BReactor_RemoveTimer(&ss, &client->disconnect_timer);
-    
-    // free stream buffer
-    StreamBuffer_Free(&client->buf);
-    
-    // free connection interfaces
-    BConnection_SendAsync_Free(&client->con);
-    BConnection_RecvAsync_Free(&client->con);
-    
-    // free connection
-    BConnection_Free(&client->con);
-    
-    // free structure
-    free(client);
-    
-    BLog(BLOG_NOTICE, "%d clients", num_clients);
-    
-    // update defense
-    update_defense();
-}
-
-void client_logfunc (struct client *client)
-{
-    char addr[BADDR_MAX_PRINT_LEN];
-    BAddr_Print(&client->addr, addr);
-    
-    BLog_Append("client (%s): ", addr);
-}
-
-void client_log (struct client *client, int level, const char *fmt, ...)
-{
-    va_list vl;
-    va_start(vl, fmt);
-    BLog_LogViaFuncVarArg((BLog_logfunc)client_logfunc, client, BLOG_CURRENT_CHANNEL, level, fmt, vl);
-    va_end(vl);
-}
-
-void client_disconnect_timer_handler (struct client *client)
-{
-    client_log(client, BLOG_INFO, "timed out, disconnecting");
-    
-    // free client
-    client_free(client);
-}
-
-void client_connection_handler (struct client *client, int event)
-{
-    if (event == BCONNECTION_EVENT_RECVCLOSED) {
-        client_log(client, BLOG_INFO, "client closed");
-    } else {
-        client_log(client, BLOG_INFO, "client error");
-    }
-    
-    // free client
-    client_free(client);
-}
-
-void update_defense (void)
-{
-#ifdef BADVPN_LINUX
-    if (options.defense_prepare_clients != -1) {
-        int val = num_clients >= options.defense_prepare_clients;
-        int res = setsockopt(listener.fd, SOL_SOCKET, SO_DOSDEF_PREPARE, &val, sizeof(val));
-        if (res < 0) {
-            BLog(BLOG_ERROR, "failed to %s defense preparation", (val ? "enable" : "disable"));
-        } else {
-            if (!defense_prepare && val) {
-                BLog(BLOG_NOTICE, "defense preparation enabled");
-            }
-            else if (defense_prepare && !val) {
-                BLog(BLOG_NOTICE, "defense preparation disabled");
-            }
-        }
-        defense_prepare = val;
-    }
-    
-    if (options.defense_activate_clients != -1) {
-        int val = num_clients >= options.defense_activate_clients;
-        int res = setsockopt(listener.fd, SOL_SOCKET, SO_DOSDEF_ACTIVATE, &val, sizeof(val));
-        if (res < 0) {
-            BLog(BLOG_ERROR, "failed to %s defense activation", (val ? "enable" : "disable"));
-        } else {
-            if (!defense_activate && val) {
-                BLog(BLOG_NOTICE, "defense activation enabled");
-            }
-            else if (defense_activate && !val) {
-                BLog(BLOG_NOTICE, "defense activation disabled");
-            }
-        }
-        defense_activate = val;
-    }
-#endif
-}
diff --git a/external/badvpn_dns/examples/CMakeLists.txt b/external/badvpn_dns/examples/CMakeLists.txt
deleted file mode 100644
index 27dbeaa..0000000
--- a/external/badvpn_dns/examples/CMakeLists.txt
+++ /dev/null
@@ -1,97 +0,0 @@
-if (NOT EMSCRIPTEN)
-    add_executable(btimer_example btimer_example.c)
-    target_link_libraries(btimer_example system)
-endif ()
-
-if (BUILDING_PREDICATE)
-    add_executable(predicate_test predicate_test.c)
-    target_link_libraries(predicate_test predicate)
-endif ()
-
-if (NOT EMSCRIPTEN)
-    add_executable(fairqueue_test fairqueue_test.c)
-    target_link_libraries(fairqueue_test system flow)
-endif ()
-
-add_executable(indexedlist_test indexedlist_test.c)
-
-if (BUILDING_SECURITY)
-    add_executable(fairqueue_test2 fairqueue_test2.c)
-    target_link_libraries(fairqueue_test2 system flow security)
-
-    add_executable(bavl_test bavl_test.c)
-    target_link_libraries(bavl_test security)
-
-    add_executable(savl_test savl_test.c)
-    target_link_libraries(savl_test security)
-
-    add_executable(bencryption_bench bencryption_bench.c)
-    target_link_libraries(bencryption_bench system security)
-endif ()
-
-if (BUILD_NCD)
-    add_executable(ncd_tokenizer_test ncd_tokenizer_test.c)
-    target_link_libraries(ncd_tokenizer_test ncdtokenizer)
-
-    add_executable(ncd_parser_test ncd_parser_test.c)
-    target_link_libraries(ncd_parser_test ncdconfigparser ncdvalgenerator ncdsugar)
-
-    add_executable(ncd_value_parser_test ncd_value_parser_test.c)
-    target_link_libraries(ncd_value_parser_test ncdvalparser ncdvalgenerator)
-
-    if (NOT EMSCRIPTEN)
-        add_executable(ncdinterfacemonitor_test ncdinterfacemonitor_test.c)
-        target_link_libraries(ncdinterfacemonitor_test ncdinterfacemonitor)
-    endif ()
-
-    add_executable(ncdval_test ncdval_test.c)
-    target_link_libraries(ncdval_test ncdval)
-    
-    add_executable(ncdvalcons_test ncdvalcons_test.c)
-    target_link_libraries(ncdvalcons_test ncdvalcons ncdvalgenerator)
-endif ()
-
-if (BUILDING_UDEVMONITOR)
-    add_executable(ncdudevmonitor_test ncdudevmonitor_test.c)
-    target_link_libraries(ncdudevmonitor_test udevmonitor)
-
-    add_executable(ncdudevmanager_test ncdudevmanager_test.c)
-    target_link_libraries(ncdudevmanager_test udevmonitor)
-endif ()
-
-if (NOT WIN32 AND NOT EMSCRIPTEN)
-    add_executable(bprocess_example bprocess_example.c)
-    target_link_libraries(bprocess_example system)
-
-    add_executable(stdin_input stdin_input.c)
-    target_link_libraries(stdin_input system flow flowextra)
-endif ()
-
-if (BUILDING_DHCPCLIENT)
-    add_executable(dhcpclient_test dhcpclient_test.c)
-    target_link_libraries(dhcpclient_test dhcpclient)
-endif ()
-
-if (BUILDING_ARPPROBE)
-    add_executable(arpprobe_test arpprobe_test.c)
-    target_link_libraries(arpprobe_test arpprobe)
-endif ()
-
-add_executable(substring_test substring_test.c)
-
-if (NOT WIN32)
-    add_executable(ipaddr6_test ipaddr6_test.c)
-    add_executable(parse_number_test parse_number_test.c)
-endif ()
-
-if (BUILDING_RANDOM)
-    add_executable(brandom2_test brandom2_test.c)
-    target_link_libraries(brandom2_test badvpn_random)
-endif ()
-
-add_executable(cavl_test cavl_test.c)
-
-if (EMSCRIPTEN)
-    add_executable(emscripten_test emscripten_test.c)
-    target_link_libraries(emscripten_test system)
-endif ()
diff --git a/external/badvpn_dns/examples/FastPacketSource.h b/external/badvpn_dns/examples/FastPacketSource.h
deleted file mode 100644
index e13e2f2..0000000
--- a/external/badvpn_dns/examples/FastPacketSource.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * @file FastPacketSource.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _FASTPACKETSOURCE_H
-#define _FASTPACKETSOURCE_H
-
-#include <stdint.h>
-#include <string.h>
-
-#include <misc/debug.h>
-#include <base/DebugObject.h>
-#include <flow/PacketPassInterface.h>
-
-typedef struct {
-    PacketPassInterface *output;
-    int psize;
-    uint8_t *data;
-    int data_len;
-    DebugObject d_obj;
-} FastPacketSource;
-
-static void _FastPacketSource_output_handler_done (FastPacketSource *s)
-{
-    DebugObject_Access(&s->d_obj);
-    
-    PacketPassInterface_Sender_Send(s->output, s->data, s->data_len);
-}
-
-static void FastPacketSource_Init (FastPacketSource *s, PacketPassInterface *output, uint8_t *data, int data_len, BPendingGroup *pg)
-{
-    ASSERT(data_len >= 0)
-    ASSERT(data_len <= PacketPassInterface_GetMTU(output));
-    
-    // init arguments
-    s->output = output;
-    s->data = data;
-    s->data_len = data_len;
-    
-    // init output
-    PacketPassInterface_Sender_Init(s->output, (PacketPassInterface_handler_done)_FastPacketSource_output_handler_done, s);
-    
-    // schedule send
-    PacketPassInterface_Sender_Send(s->output, s->data, s->data_len);
-    
-    DebugObject_Init(&s->d_obj);
-}
-
-static void FastPacketSource_Free (FastPacketSource *s)
-{
-    DebugObject_Free(&s->d_obj);
-}
-
-#endif
diff --git a/external/badvpn_dns/examples/RandomPacketSink.h b/external/badvpn_dns/examples/RandomPacketSink.h
deleted file mode 100644
index cbadf78..0000000
--- a/external/badvpn_dns/examples/RandomPacketSink.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * @file RandomPacketSink.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _RANDOMPACKETSINK_H
-#define _RANDOMPACKETSINK_H
-
-#include <stdio.h>
-
-#include <misc/debug.h>
-#include <security/BRandom.h>
-#include <system/BReactor.h>
-#include <base/DebugObject.h>
-#include <flow/PacketPassInterface.h>
-
-typedef struct {
-    BReactor *reactor;
-    PacketPassInterface input;
-    BTimer timer;
-    DebugObject d_obj;
-} RandomPacketSink;
-
-static void _RandomPacketSink_input_handler_send (RandomPacketSink *s, uint8_t *data, int data_len)
-{
-    DebugObject_Access(&s->d_obj);
-    
-    printf("sink: send '");
-    size_t res = fwrite(data, data_len, 1, stdout);
-    B_USE(res)
-    
-    uint8_t r;
-    BRandom_randomize(&r, sizeof(r));
-    if (r&(uint8_t)1) {
-        printf("' accepting\n");
-        PacketPassInterface_Done(&s->input);
-    } else {
-        printf("' delaying\n");
-        BReactor_SetTimer(s->reactor, &s->timer);
-    }
-}
-
-static void _RandomPacketSink_input_handler_requestcancel (RandomPacketSink *s)
-{
-    DebugObject_Access(&s->d_obj);
-    
-    printf("sink: cancelled\n");
-    BReactor_RemoveTimer(s->reactor, &s->timer);
-    PacketPassInterface_Done(&s->input);
-}
-
-static void _RandomPacketSink_timer_handler (RandomPacketSink *s)
-{
-    DebugObject_Access(&s->d_obj);
-    
-    PacketPassInterface_Done(&s->input);
-}
-
-static void RandomPacketSink_Init (RandomPacketSink *s, BReactor *reactor, int mtu, int ms)
-{
-    // init arguments
-    s->reactor = reactor;
-    
-    // init input
-    PacketPassInterface_Init(&s->input, mtu, (PacketPassInterface_handler_send)_RandomPacketSink_input_handler_send, s, BReactor_PendingGroup(reactor));
-    PacketPassInterface_EnableCancel(&s->input, (PacketPassInterface_handler_requestcancel)_RandomPacketSink_input_handler_requestcancel);
-    
-    // init timer
-    BTimer_Init(&s->timer, ms, (BTimer_handler)_RandomPacketSink_timer_handler, s);
-    
-    DebugObject_Init(&s->d_obj);
-}
-
-static void RandomPacketSink_Free (RandomPacketSink *s)
-{
-    DebugObject_Free(&s->d_obj);
-    
-    // free timer
-    BReactor_RemoveTimer(s->reactor, &s->timer);
-    
-    // free input
-    PacketPassInterface_Free(&s->input);
-}
-
-static PacketPassInterface * RandomPacketSink_GetInput (RandomPacketSink *s)
-{
-    DebugObject_Access(&s->d_obj);
-    
-    return &s->input;
-}
-
-#endif
diff --git a/external/badvpn_dns/examples/TimerPacketSink.h b/external/badvpn_dns/examples/TimerPacketSink.h
deleted file mode 100644
index e1e8217..0000000
--- a/external/badvpn_dns/examples/TimerPacketSink.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * @file TimerPacketSink.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _TIMERPACKETSINK_H
-#define _TIMERPACKETSINK_H
-
-#include <stdio.h>
-
-#include <misc/debug.h>
-#include <system/BReactor.h>
-#include <flow/PacketPassInterface.h>
-
-typedef struct {
-    BReactor *reactor;
-    PacketPassInterface input;
-    BTimer timer;
-} TimerPacketSink;
-
-static void _TimerPacketSink_input_handler_send (TimerPacketSink *s, uint8_t *data, int data_len)
-{
-    printf("sink: send '");
-    size_t res = fwrite(data, data_len, 1, stdout);
-    B_USE(res)
-    printf("'\n");
-    
-    BReactor_SetTimer(s->reactor, &s->timer);
-}
-
-static void _TimerPacketSink_input_handler_requestcancel (TimerPacketSink *s)
-{
-    printf("sink: cancelled\n");
-    
-    BReactor_RemoveTimer(s->reactor, &s->timer);
-    PacketPassInterface_Done(&s->input);
-}
-
-static void _TimerPacketSink_timer_handler (TimerPacketSink *s)
-{
-    printf("sink: done\n");
-    
-    PacketPassInterface_Done(&s->input);
-}
-
-static void TimerPacketSink_Init (TimerPacketSink *s, BReactor *reactor, int mtu, int ms)
-{
-    // init arguments
-    s->reactor = reactor;
-    
-    // init input
-    PacketPassInterface_Init(&s->input, mtu, (PacketPassInterface_handler_send)_TimerPacketSink_input_handler_send, s, BReactor_PendingGroup(s->reactor));
-    PacketPassInterface_EnableCancel(&s->input, (PacketPassInterface_handler_requestcancel)_TimerPacketSink_input_handler_requestcancel);
-    
-    // init timer
-    BTimer_Init(&s->timer, ms, (BTimer_handler)_TimerPacketSink_timer_handler, s);
-}
-
-static void TimerPacketSink_Free (TimerPacketSink *s)
-{
-    // free timer
-    BReactor_RemoveTimer(s->reactor, &s->timer);
-    
-    // free input
-    PacketPassInterface_Free(&s->input);
-}
-
-static PacketPassInterface * TimerPacketSink_GetInput (TimerPacketSink *s)
-{
-    return &s->input;
-}
-
-#endif
diff --git a/external/badvpn_dns/examples/arpprobe_test.c b/external/badvpn_dns/examples/arpprobe_test.c
deleted file mode 100644
index d075f52..0000000
--- a/external/badvpn_dns/examples/arpprobe_test.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * @file arpprobe_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stddef.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <misc/debug.h>
-#include <base/DebugObject.h>
-#include <base/BLog.h>
-#include <system/BReactor.h>
-#include <system/BSignal.h>
-#include <system/BTime.h>
-#include <system/BNetwork.h>
-#include <arpprobe/BArpProbe.h>
-
-BReactor reactor;
-BArpProbe arpprobe;
-
-static void signal_handler (void *user);
-static void arpprobe_handler (void *unused, int event);
-
-int main (int argc, char **argv)
-{
-    if (argc <= 0) {
-        return 1;
-    }
-    
-    if (argc != 3) {
-        printf("Usage: %s <interface> <addr>\n", argv[0]);
-        goto fail0;
-    }
-    
-    char *ifname = argv[1];
-    uint32_t addr = inet_addr(argv[2]);
-    
-    BTime_Init();
-    
-    BLog_InitStdout();
-    
-    if (!BNetwork_GlobalInit()) {
-        DEBUG("BNetwork_GlobalInit failed");
-        goto fail1;
-    }
-    
-    if (!BReactor_Init(&reactor)) {
-        DEBUG("BReactor_Init failed");
-        goto fail1;
-    }
-    
-    if (!BSignal_Init(&reactor, signal_handler, NULL)) {
-        DEBUG("BSignal_Init failed");
-        goto fail2;
-    }
-    
-    if (!BArpProbe_Init(&arpprobe, ifname, addr, &reactor, NULL, arpprobe_handler)) {
-        DEBUG("BArpProbe_Init failed");
-        goto fail3;
-    }
-    
-    BReactor_Exec(&reactor);
-    
-    BArpProbe_Free(&arpprobe);
-fail3:
-    BSignal_Finish();
-fail2:
-    BReactor_Free(&reactor);
-fail1:
-    BLog_Free();
-fail0:
-    DebugObjectGlobal_Finish();
-    
-    return 1;
-}
-
-void signal_handler (void *user)
-{
-    DEBUG("termination requested");
-    
-    BReactor_Quit(&reactor, 0);
-}
-
-void arpprobe_handler (void *unused, int event)
-{
-    switch (event) {
-        case BARPPROBE_EVENT_EXIST: {
-            printf("ARPPROBE: exist\n");
-        } break;
-        
-        case BARPPROBE_EVENT_NOEXIST: {
-            printf("ARPPROBE: noexist\n");
-        } break;
-        
-        case BARPPROBE_EVENT_ERROR: {
-            printf("ARPPROBE: error\n");
-            
-            // exit reactor
-            BReactor_Quit(&reactor, 0);
-        } break;
-        
-        default:
-            ASSERT(0);
-    }
-}
diff --git a/external/badvpn_dns/examples/bavl_test.c b/external/badvpn_dns/examples/bavl_test.c
deleted file mode 100644
index c30ae6f..0000000
--- a/external/badvpn_dns/examples/bavl_test.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/**
- * @file bavl_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-
-#include <misc/offset.h>
-#include <misc/debug.h>
-#include <misc/balloc.h>
-#include <misc/compare.h>
-#include <structure/BAVL.h>
-#include <security/BRandom.h>
-
-struct mynode {
-    int used;
-    int num;
-    BAVLNode avl_node;
-};
-
-static int int_comparator (void *user, int *val1, int *val2)
-{
-    return B_COMPARE(*val1, *val2);
-}
-
-static void verify (BAVL *tree)
-{
-    printf("Verifying...\n");
-    BAVL_Verify(tree);
-}
-
-int main (int argc, char **argv)
-{
-    int num_nodes;
-    int num_random_delete;
-    
-    if (argc != 3 || (num_nodes = atoi(argv[1])) <= 0 || (num_random_delete = atoi(argv[2])) < 0) {
-        fprintf(stderr, "Usage: %s <num> <numrandomdelete>\n", (argc > 0 ? argv[0] : NULL));
-        return 1;
-    }
-    
-    struct mynode *nodes = (struct mynode *)BAllocArray(num_nodes, sizeof(*nodes));
-    ASSERT_FORCE(nodes)
-    
-    int *values_ins = (int *)BAllocArray(num_nodes, sizeof(int));
-    ASSERT_FORCE(values_ins)
-    
-    int *values = (int *)BAllocArray(num_random_delete, sizeof(int));
-    ASSERT_FORCE(values)
-    
-    BAVL avl;
-    BAVL_Init(&avl, OFFSET_DIFF(struct mynode, num, avl_node), (BAVL_comparator)int_comparator, NULL);
-    verify(&avl);
-    
-    printf("Inserting random values...\n");
-    int inserted = 0;
-    BRandom_randomize((uint8_t *)values_ins, num_nodes * sizeof(int));
-    for (int i = 0; i < num_nodes; i++) {
-        nodes[i].num = values_ins[i];
-        if (BAVL_Insert(&avl, &nodes[i].avl_node, NULL)) {
-            nodes[i].used = 1;
-            inserted++;
-        } else {
-            nodes[i].used = 0;
-            printf("Insert collision!\n");
-        }
-    }
-    printf("Inserted %d entries\n", inserted);
-    verify(&avl);
-    
-    printf("Removing random entries...\n");
-    int removed1 = 0;
-    BRandom_randomize((uint8_t *)values, num_random_delete * sizeof(int));
-    for (int i = 0; i < num_random_delete; i++) {
-        int index = (((unsigned int *)values)[i] % num_nodes);
-        struct mynode *node = nodes + index;
-        if (node->used) {
-            BAVL_Remove(&avl, &node->avl_node);
-            node->used = 0;
-            removed1++;
-        }
-    }
-    printf("Removed %d entries\n", removed1);
-    verify(&avl);
-    
-    printf("Removing remaining...\n");
-    int removed2 = 0;
-    while (!BAVL_IsEmpty(&avl)) {
-        struct mynode *node = UPPER_OBJECT(BAVL_GetFirst(&avl), struct mynode, avl_node);
-        ASSERT_FORCE(node->used)
-        BAVL_Remove(&avl, &node->avl_node);
-        node->used = 0;
-        removed2++;
-    }
-    printf("Removed %d entries\n", removed2);
-    ASSERT_FORCE(BAVL_IsEmpty(&avl))
-    ASSERT_FORCE(removed1 + removed2 == inserted)
-    verify(&avl);
-    
-    BFree(nodes);
-    BFree(values_ins);
-    BFree(values);
-    
-    return 0;
-}
diff --git a/external/badvpn_dns/examples/bencryption_bench.c b/external/badvpn_dns/examples/bencryption_bench.c
deleted file mode 100644
index c842bf2..0000000
--- a/external/badvpn_dns/examples/bencryption_bench.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/**
- * @file bencryption_bench.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <limits.h>
-
-#include <misc/balloc.h>
-#include <security/BRandom.h>
-#include <security/BEncryption.h>
-#include <base/DebugObject.h>
-
-static void usage (char *name)
-{
-    printf(
-        "Usage: %s <enc/dec> <ciper> <num_blocks> <num_ops>\n"
-        "    <cipher> is one of (blowfish, aes).\n",
-        name
-    );
-    
-    exit(1);
-}
-
-int main (int argc, char **argv)
-{
-    if (argc <= 0) {
-        return 1;
-    }
-    
-    if (argc != 5) {
-        usage(argv[0]);
-    }
-    
-    char *mode_str = argv[1];
-    char *cipher_str = argv[2];
-    
-    int mode;
-    int cipher = 0; // silence warning
-    int num_blocks = atoi(argv[3]);
-    int num_ops = atoi(argv[4]);
-    
-    if (!strcmp(mode_str, "enc")) {
-        mode = BENCRYPTION_MODE_ENCRYPT;
-    }
-    else if (!strcmp(mode_str, "dec")) {
-        mode = BENCRYPTION_MODE_DECRYPT;
-    }
-    else {
-        usage(argv[0]);
-    }
-    
-    if (!strcmp(cipher_str, "blowfish")) {
-        cipher = BENCRYPTION_CIPHER_BLOWFISH;
-    }
-    else if (!strcmp(cipher_str, "aes")) {
-        cipher = BENCRYPTION_CIPHER_AES;
-    }
-    else {
-        usage(argv[0]);
-    }
-    
-    if (num_blocks < 0 || num_ops < 0) {
-        usage(argv[0]);
-    }
-    
-    int key_size = BEncryption_cipher_key_size(cipher);
-    int block_size = BEncryption_cipher_block_size(cipher);
-    
-    uint8_t key[BENCRYPTION_MAX_KEY_SIZE];
-    BRandom_randomize(key, key_size);
-    
-    uint8_t iv[BENCRYPTION_MAX_BLOCK_SIZE];
-    BRandom_randomize(iv, block_size);
-    
-    if (num_blocks > INT_MAX / block_size) {
-        printf("too much");
-        goto fail0;
-    }
-    int unit_size = num_blocks * block_size;
-    
-    printf("unit size %d\n", unit_size);
-    
-    uint8_t *buf1 = (uint8_t *)BAlloc(unit_size);
-    if (!buf1) {
-        printf("BAlloc failed");
-        goto fail0;
-    }
-    
-    uint8_t *buf2 = (uint8_t *)BAlloc(unit_size);
-    if (!buf2) {
-        printf("BAlloc failed");
-        goto fail1;
-    }
-    
-    BEncryption enc;
-    BEncryption_Init(&enc, mode, cipher, key);
-    
-    uint8_t *in = buf1;
-    uint8_t *out = buf2;
-    BRandom_randomize(in, unit_size);
-    
-    for (int i = 0; i < num_ops; i++) {
-        BEncryption_Encrypt(&enc, in, out, unit_size, iv);
-        
-        uint8_t *t = in;
-        in = out;
-        out = t;
-    }
-    
-    BEncryption_Free(&enc);
-    BFree(buf2);
-fail1:
-    BFree(buf1);
-fail0:
-    DebugObjectGlobal_Finish();
-    
-    return 0;
-}
diff --git a/external/badvpn_dns/examples/bprocess_example.c b/external/badvpn_dns/examples/bprocess_example.c
deleted file mode 100644
index 0ece996..0000000
--- a/external/badvpn_dns/examples/bprocess_example.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/**
- * @file bprocess_example.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stddef.h>
-#include <unistd.h>
-
-#include <misc/debug.h>
-#include <base/DebugObject.h>
-#include <base/BLog.h>
-#include <system/BReactor.h>
-#include <system/BUnixSignal.h>
-#include <system/BTime.h>
-#include <system/BProcess.h>
-
-BReactor reactor;
-BUnixSignal unixsignal;
-BProcessManager manager;
-BProcess process;
-
-static void unixsignal_handler (void *user, int signo);
-static void process_handler (void *user, int normally, uint8_t normally_exit_status);
-
-int main (int argc, char **argv)
-{
-    if (argc <= 0) {
-        return 1;
-    }
-    
-    int ret = 1;
-    
-    if (argc < 2) {
-        printf("Usage: %s <program> [argument ...]\n", argv[0]);
-        goto fail0;
-    }
-    
-    char *program = argv[1];
-    
-    // init time
-    BTime_Init();
-    
-    // init logger
-    BLog_InitStdout();
-    
-    // init reactor (event loop)
-    if (!BReactor_Init(&reactor)) {
-        DEBUG("BReactor_Init failed");
-        goto fail1;
-    }
-    
-    // choose signals to catch
-    sigset_t set;
-    sigemptyset(&set);
-    sigaddset(&set, SIGINT);
-    sigaddset(&set, SIGTERM);
-    
-    // init BUnixSignal for catching signals
-    if (!BUnixSignal_Init(&unixsignal, &reactor, set, unixsignal_handler, NULL)) {
-        DEBUG("BUnixSignal_Init failed");
-        goto fail2;
-    }
-    
-    // init process manager
-    if (!BProcessManager_Init(&manager, &reactor)) {
-        DEBUG("BProcessManager_Init failed");
-        goto fail3;
-    }
-    
-    char **p_argv = argv + 1;
-    
-    // map fds 0, 1, 2 in child to fds 0, 1, 2 in parent
-    int fds[] = { 0, 1, 2, -1 };
-    int fds_map[] = { 0, 1, 2 };
-    
-    // start child process
-    if (!BProcess_InitWithFds(&process, &manager, process_handler, NULL, program, p_argv, NULL, fds, fds_map)) {
-        DEBUG("BProcess_Init failed");
-        goto fail4;
-    }
-    
-    // enter event loop
-    ret = BReactor_Exec(&reactor);
-    
-    BProcess_Free(&process);
-fail4:
-    BProcessManager_Free(&manager);
-fail3:
-    BUnixSignal_Free(&unixsignal, 0);
-fail2:
-    BReactor_Free(&reactor);
-fail1:
-    BLog_Free();
-fail0:
-    DebugObjectGlobal_Finish();
-    
-    return ret;
-}
-
-void unixsignal_handler (void *user, int signo)
-{
-    DEBUG("received %s, terminating child", (signo == SIGINT ? "SIGINT" : "SIGTERM"));
-    
-    // send SIGTERM to child
-    BProcess_Terminate(&process);
-}
-
-void process_handler (void *user, int normally, uint8_t normally_exit_status)
-{
-    DEBUG("process terminated");
-    
-    int ret = (normally ? normally_exit_status : 1);
-    
-    // return from event loop
-    BReactor_Quit(&reactor, ret);
-}
diff --git a/external/badvpn_dns/examples/brandom2_test.c b/external/badvpn_dns/examples/brandom2_test.c
deleted file mode 100644
index 539735c..0000000
--- a/external/badvpn_dns/examples/brandom2_test.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * @file brandom2_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <inttypes.h>
-
-#include <misc/debug.h>
-#include <random/BRandom2.h>
-
-#define NUM_NUMBERS 10
-
-static BRandom2 brandom;
-
-int main (int argc, char *argv[])
-{
-    int ret = 1;
-    
-    if (!BRandom2_Init(&brandom, 0)) {
-        DEBUG("BRandom2_Init failed");
-        goto fail0;
-    }
-    
-    uint32_t numbers[NUM_NUMBERS];
-    if (!BRandom2_GenBytes(&brandom, numbers, sizeof(numbers))) {
-        DEBUG("BRandom2_GenBytes failed");
-        goto fail1;
-    }
-    
-    for (int i = 0; i < NUM_NUMBERS; i++) {
-        printf("%"PRIu32"\n", numbers[i]);
-    }
-    
-    ret = 0;
-    
-fail1:
-    BRandom2_Free(&brandom);
-fail0:
-    return ret;
-}
diff --git a/external/badvpn_dns/examples/btimer_example.c b/external/badvpn_dns/examples/btimer_example.c
deleted file mode 100644
index c4d8d54..0000000
--- a/external/badvpn_dns/examples/btimer_example.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * @file btimer_example.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-
-#include <system/BReactor.h>
-#include <base/BLog.h>
-#include <system/BTime.h>
-
-// gives average firing rate 100kHz
-#define TIMER_NUM 500
-#define TIMER_MODULO 10
-
-BReactor sys;
-
-void handle_timer (BTimer *bt)
-{
-    #ifdef BADVPN_USE_WINAPI
-    btime_t time = btime_gettime() + rand()%TIMER_MODULO;
-    #else
-    btime_t time = btime_gettime() + random()%TIMER_MODULO;
-    #endif
-    BReactor_SetTimerAbsolute(&sys, bt, time);
-}
-
-int main ()
-{
-    BLog_InitStdout();
-    
-    #ifdef BADVPN_USE_WINAPI
-    srand(time(NULL));
-    #else
-    srandom(time(NULL));
-    #endif
-    
-    // init time
-    BTime_Init();
-
-    if (!BReactor_Init(&sys)) {
-        DEBUG("BReactor_Init failed");
-        return 1;
-    }
-    
-    BTimer timers[TIMER_NUM];
-
-    int i;
-    for (i=0; i<TIMER_NUM; i++) {
-        BTimer *timer = &timers[i];
-        BTimer_Init(timer, 0, (BTimer_handler)handle_timer, timer);
-        BReactor_SetTimer(&sys, timer);
-    }
-    
-    int ret = BReactor_Exec(&sys);
-    BReactor_Free(&sys);
-    return ret;
-}
diff --git a/external/badvpn_dns/examples/cavl_test.c b/external/badvpn_dns/examples/cavl_test.c
deleted file mode 100644
index 61fcbd6..0000000
--- a/external/badvpn_dns/examples/cavl_test.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/**
- * @file cavl_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <stdint.h>
-#include <limits.h>
-
-#include <misc/balloc.h>
-#include <misc/compare.h>
-#include <misc/debug.h>
-#include <misc/print_macros.h>
-#include <structure/CAvl.h>
-
-#define USE_COUNTS 0
-#define USE_ASSOC 1
-
-typedef size_t entry_index;
-#define MAX_INDICES SIZE_MAX
-
-typedef uint32_t entry_key;
-
-typedef uint8_t assoc_value;
-typedef uint64_t assoc_sum;
-
-struct entry {
-    entry_index tree_child[2];
-    entry_index tree_parent;
-    int8_t tree_balance;
-#if USE_COUNTS
-    size_t tree_count;
-#endif
-#if USE_ASSOC
-    assoc_value assoc_value;
-    assoc_sum assoc_sum;
-#endif
-    entry_key key;
-};
-
-typedef struct entry *entry_ptr;
-
-#include "cavl_test_tree.h"
-#include <structure/CAvl_decl.h>
-
-#include "cavl_test_tree.h"
-#include <structure/CAvl_impl.h>
-
-static void random_bytes (char *buf, size_t len)
-{
-    while (len > 0) {
-        *((unsigned char *)buf) = rand();
-        buf++;
-        len--;
-    }
-}
-
-static int uint64_less (void *user, uint64_t a, uint64_t b)
-{
-    return (a < b);
-}
-
-#if USE_ASSOC
-static MyTreeRef assoc_continue_last_lesser_equal (MyTree *tree, struct entry *arg, MyTreeRef ref, assoc_sum target_sum)
-{
-    assoc_sum cur_sum = MyTree_ExclusiveAssocPrefixSum(tree, arg, ref);
-    ASSERT(target_sum >= cur_sum)
-    while (cur_sum + ref.ptr->assoc_value <= target_sum) {
-        MyTreeRef next_ref = MyTree_GetNext(tree, arg, ref);
-        if (next_ref.link == -1) {
-            break;
-        }
-        cur_sum += ref.ptr->assoc_value;
-        ref = next_ref;
-    }
-    return ref;
-}
-#endif
-
-static void test_assoc (MyTree *tree, struct entry *arg)
-{
-#if USE_ASSOC
-    assoc_sum sum = 0;
-    for (MyTreeRef ref = MyTree_GetFirst(tree, arg); ref.link != -1; ref = MyTree_GetNext(tree, arg, ref)) {
-        assoc_sum tree_sum = MyTree_ExclusiveAssocPrefixSum(tree, arg, ref);
-        ASSERT_FORCE(tree_sum == sum);
-        ASSERT_FORCE(MyTree_FindLastExclusiveAssocPrefixSumLesserEqual(tree, arg, sum, uint64_less, NULL).link == assoc_continue_last_lesser_equal(tree, arg, ref, sum).link);
-        ASSERT_FORCE(MyTree_FindLastExclusiveAssocPrefixSumLesserEqual(tree, arg, sum + 1, uint64_less, NULL).link == assoc_continue_last_lesser_equal(tree, arg, ref, sum + 1).link);
-        sum += ref.ptr->assoc_value;
-    }
-    ASSERT_FORCE(sum == MyTree_AssocSum(tree, arg));
-#endif
-}
-
-int main (int argc, char *argv[])
-{
-    //srand(time(NULL));
-    
-    printf("sizeof(struct entry)=%" PRIsz "\n", sizeof(struct entry));
-    
-    if (argc != 6) {
-        fprintf(stderr, "Usage: %s <num_keys> <num_lookups> <num_remove> <do_remove=1/0> <do_verify=1/0>\n", (argc > 0 ? argv[0] : ""));
-        return 1;
-    }
-    
-    size_t num_keys = atoi(argv[1]);
-    size_t num_lookups = atoi(argv[2]);
-    size_t num_remove = atoi(argv[3]);
-    size_t do_remove = atoi(argv[4]);
-    size_t do_verify = atoi(argv[5]);
-    
-    printf("Allocating keys...\n");
-    entry_key *keys = (entry_key *)BAllocArray(num_keys, sizeof(keys[0]));
-    ASSERT_FORCE(keys);
-
-    printf("Generating random keys...\n");
-    random_bytes((char *)keys, num_keys * sizeof(keys[0]));
-    
-    printf("Allocating lookup indices...\n");
-    uint64_t *lookup_indices = (uint64_t *)BAllocArray(num_lookups, sizeof(lookup_indices[0]));
-    ASSERT_FORCE(lookup_indices);
-    
-    printf("Generating random lookup indices...\n");
-    random_bytes((char *)lookup_indices, num_lookups * sizeof(lookup_indices[0]));
-    
-    printf("Allocating remove indices...\n");
-    uint64_t *remove_indices = (uint64_t *)BAllocArray(num_remove, sizeof(remove_indices[0]));
-    ASSERT_FORCE(remove_indices);
-    
-    printf("Generating random remove indices...\n");
-    random_bytes((char *)remove_indices, num_remove * sizeof(remove_indices[0]));
-    
-#if USE_ASSOC
-    printf("Allocating assoc values...\n");
-    assoc_value *assoc_values = (assoc_value *)BAllocArray(num_keys, sizeof(assoc_values[0]));
-    ASSERT_FORCE(assoc_values);
-
-    printf("Generating random assoc values...\n");
-    random_bytes((char *)assoc_values, num_keys * sizeof(assoc_values[0]));
-#endif
-    
-    printf("Allocating entries...\n");
-    ASSERT_FORCE(num_keys <= MAX_INDICES);
-    struct entry *entries = (struct entry *)BAllocArray(num_keys, sizeof(*entries));
-    ASSERT_FORCE(entries);
-    entry_index num_used_entries = 0;
-    
-    MyTree tree;
-    MyTree_Init(&tree);
-    
-    struct entry *arg = entries;
-    
-    ASSERT_FORCE(MyTree_IsEmpty(&tree));
-#if USE_COUNTS
-    ASSERT_FORCE(MyTree_Count(&tree, arg) == 0);
-#endif
-    test_assoc(&tree, arg);
-    
-    size_t num;
-#if USE_COUNTS
-    size_t prevNum;
-#endif
-    
-    printf("Inserting random numbers...\n");
-    num = 0;
-    for (size_t i = 0; i < num_keys; i++) {
-        entries[num_used_entries].key = keys[i];
-#if USE_ASSOC
-        entries[num_used_entries].assoc_value = assoc_values[i];
-#endif
-        MyTreeRef ref = {&entries[num_used_entries], num_used_entries};
-        if (!MyTree_Insert(&tree, arg, ref, NULL)) {
-            //printf("Insert collision!\n");
-            continue;
-        }
-        num_used_entries++;
-        num++;
-    }
-    printf("Inserted %" PRIsz ".\n", num);
-#if USE_COUNTS
-    ASSERT_FORCE(MyTree_Count(&tree, arg) == num);
-#endif
-    if (do_verify) {
-        printf("Verifying...\n");
-        MyTree_Verify(&tree, arg);
-        test_assoc(&tree, arg);
-    }
-    
-    printf("Looking up random inserted keys...\n");
-    for (size_t i = 0; i < num_lookups; i++) {
-        entry_index idx = lookup_indices[i] % num_keys;
-        MyTreeRef entry = MyTree_LookupExact(&tree, arg, keys[idx]);
-        ASSERT_FORCE(!MyTreeIsNullRef(entry));
-    }
-    
-#if USE_COUNTS
-    prevNum = MyTree_Count(&tree, arg);
-#endif
-    num = 0;
-    printf("Looking up and removing random inserted keys...\n");
-    for (size_t i = 0; i < num_remove; i++) {
-        entry_index idx = remove_indices[i] % num_keys;
-        MyTreeRef entry = MyTree_LookupExact(&tree, arg, keys[idx]);
-        if (MyTreeIsNullRef(entry)) {
-            //printf("Remove collision!\n");
-            continue;
-        }
-        ASSERT_FORCE(entry.ptr->key == keys[idx]);
-        MyTree_Remove(&tree, arg, entry);
-        num++;
-    }
-    printf("Removed %" PRIsz ".\n", num);
-#if USE_COUNTS
-    ASSERT_FORCE(MyTree_Count(&tree, arg) == prevNum - num);
-#endif
-    if (do_verify) {
-        printf("Verifying...\n");
-        MyTree_Verify(&tree, arg);
-        test_assoc(&tree, arg);
-    }
-    
-    if (do_remove) {
-#if USE_COUNTS
-        prevNum = MyTree_Count(&tree, arg);
-#endif
-        num = 0;
-        printf("Removing remaining...\n");
-        
-        MyTreeRef cur = MyTree_GetFirst(&tree, arg);
-        while (!MyTreeIsNullRef(cur)) {
-            MyTreeRef prev = cur;
-            cur = MyTree_GetNext(&tree, arg, cur);
-            MyTree_Remove(&tree, arg, prev);
-            num++;
-        }
-        
-        printf("Removed %" PRIsz ".\n", num);
-        ASSERT_FORCE(MyTree_IsEmpty(&tree));
-#if USE_COUNTS
-        ASSERT_FORCE(MyTree_Count(&tree, arg) == 0);
-        ASSERT_FORCE(num == prevNum);
-#endif
-        if (do_verify) {
-            printf("Verifying...\n");
-            MyTree_Verify(&tree, arg);
-        }
-    }
-    
-    printf("Freeing...\n");
-    BFree(keys);
-    BFree(lookup_indices);
-    BFree(remove_indices);
-#if USE_ASSOC
-    BFree(assoc_values);
-#endif
-    BFree(entries);
-    
-    return 0;
-}
diff --git a/external/badvpn_dns/examples/cavl_test_tree.h b/external/badvpn_dns/examples/cavl_test_tree.h
deleted file mode 100644
index 463076f..0000000
--- a/external/badvpn_dns/examples/cavl_test_tree.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#define CAVL_PARAM_NAME MyTree
-#define CAVL_PARAM_FEATURE_COUNTS USE_COUNTS
-#define CAVL_PARAM_FEATURE_KEYS_ARE_INDICES 0
-#define CAVL_PARAM_FEATURE_ASSOC USE_ASSOC
-#define CAVL_PARAM_TYPE_ENTRY struct entry
-#define CAVL_PARAM_TYPE_LINK entry_index
-#define CAVL_PARAM_TYPE_KEY entry_key
-#define CAVL_PARAM_TYPE_ARG entry_ptr
-#define CAVL_PARAM_TYPE_COUNT size_t
-#define CAVL_PARAM_TYPE_ASSOC assoc_sum
-#define CAVL_PARAM_VALUE_COUNT_MAX SIZE_MAX
-#define CAVL_PARAM_VALUE_NULL ((entry_index)-1)
-#define CAVL_PARAM_VALUE_ASSOC_ZERO 0
-#define CAVL_PARAM_FUN_DEREF(arg, link) (&(arg)[(link)])
-#define CAVL_PARAM_FUN_COMPARE_ENTRIES(arg, entry1, entry2) B_COMPARE((entry1).ptr->key, (entry2).ptr->key)
-#define CAVL_PARAM_FUN_COMPARE_KEY_ENTRY(arg, key1, entry2) B_COMPARE((key1), (entry2).ptr->key)
-#define CAVL_PARAM_FUN_ASSOC_VALUE(arg, entry) ((entry).ptr->assoc_value)
-#define CAVL_PARAM_FUN_ASSOC_OPER(arg, value1, value2) ((value1) + (value2))
-#define CAVL_PARAM_MEMBER_CHILD tree_child
-#define CAVL_PARAM_MEMBER_BALANCE tree_balance
-#define CAVL_PARAM_MEMBER_PARENT tree_parent
-#define CAVL_PARAM_MEMBER_COUNT tree_count
-#define CAVL_PARAM_MEMBER_ASSOC assoc_sum
diff --git a/external/badvpn_dns/examples/dhcpclient_test.c b/external/badvpn_dns/examples/dhcpclient_test.c
deleted file mode 100644
index 9601c01..0000000
--- a/external/badvpn_dns/examples/dhcpclient_test.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * @file dhcpclient_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stddef.h>
-
-#include <misc/debug.h>
-#include <base/DebugObject.h>
-#include <base/BLog.h>
-#include <system/BReactor.h>
-#include <system/BSignal.h>
-#include <system/BTime.h>
-#include <system/BNetwork.h>
-#include <dhcpclient/BDHCPClient.h>
-
-BReactor reactor;
-BRandom2 random2;
-BDHCPClient dhcp;
-
-static void signal_handler (void *user);
-static void dhcp_handler (void *unused, int event);
-
-int main (int argc, char **argv)
-{
-    if (argc <= 0) {
-        return 1;
-    }
-    
-    if (argc != 2) {
-        printf("Usage: %s <interface>\n", argv[0]);
-        goto fail0;
-    }
-    
-    char *ifname = argv[1];
-    
-    BTime_Init();
-    
-    BLog_InitStdout();
-    
-    if (!BNetwork_GlobalInit()) {
-        DEBUG("BNetwork_GlobalInit failed");
-        goto fail1;
-    }
-    
-    if (!BReactor_Init(&reactor)) {
-        DEBUG("BReactor_Init failed");
-        goto fail1;
-    }
-    
-    if (!BRandom2_Init(&random2, 0)) {
-        DEBUG("BRandom2_Init failed");
-        goto fail1a;
-    }
-    
-    if (!BSignal_Init(&reactor, signal_handler, NULL)) {
-        DEBUG("BSignal_Init failed");
-        goto fail2;
-    }
-    
-    struct BDHCPClient_opts opts = {};
-    
-    if (!BDHCPClient_Init(&dhcp, ifname, opts, &reactor, &random2, dhcp_handler, NULL)) {
-        DEBUG("BDHCPClient_Init failed");
-        goto fail3;
-    }
-    
-    BReactor_Exec(&reactor);
-    
-    BDHCPClient_Free(&dhcp);
-fail3:
-    BSignal_Finish();
-fail2:
-    BRandom2_Free(&random2);
-fail1a:
-    BReactor_Free(&reactor);
-fail1:
-    BLog_Free();
-fail0:
-    DebugObjectGlobal_Finish();
-    
-    return 1;
-}
-
-void signal_handler (void *user)
-{
-    DEBUG("termination requested");
-    
-    BReactor_Quit(&reactor, 0);
-}
-
-void dhcp_handler (void *unused, int event)
-{
-    switch (event) {
-        case BDHCPCLIENT_EVENT_UP: {
-            printf("DHCP: up");
-            
-            uint32_t ip;
-            uint8_t *ipb = (void *)&ip;
-            
-            BDHCPClient_GetClientIP(&dhcp, &ip);
-            printf(" IP=%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8, ipb[0], ipb[1], ipb[2], ipb[3]);
-            
-            BDHCPClient_GetClientMask(&dhcp, &ip);
-            printf(" Mask=%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8, ipb[0], ipb[1], ipb[2], ipb[3]);
-            
-            if (BDHCPClient_GetRouter(&dhcp, &ip)) {
-                printf(" Router=%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8, ipb[0], ipb[1], ipb[2], ipb[3]);
-            }
-            
-            uint32_t dns[BDHCPCLIENT_MAX_DOMAIN_NAME_SERVERS];
-            int num = BDHCPClient_GetDNS(&dhcp, dns, BDHCPCLIENT_MAX_DOMAIN_NAME_SERVERS);
-            for (int i = 0; i < num; i++) {
-                ip=dns[i];
-                printf(" DNS=%"PRIu8".%"PRIu8".%"PRIu8".%"PRIu8, ipb[0], ipb[1], ipb[2], ipb[3]);
-            }
-            
-            printf("\n");
-        } break;
-        
-        case BDHCPCLIENT_EVENT_DOWN: {
-            printf("DHCP: down\n");
-        } break;
-        
-        case BDHCPCLIENT_EVENT_ERROR: {
-            printf("DHCP: error\n");
-            
-            // exit reactor
-            BReactor_Quit(&reactor, 0);
-        } break;
-        
-        default:
-            ASSERT(0);
-    }
-}
diff --git a/external/badvpn_dns/examples/emscripten_test.c b/external/badvpn_dns/examples/emscripten_test.c
deleted file mode 100644
index 52b0351..0000000
--- a/external/badvpn_dns/examples/emscripten_test.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * @file emscripten_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-#include <emscripten/emscripten.h>
-
-#include <misc/debug.h>
-#include <system/BTime.h>
-#include <system/BReactor.h>
-
-BReactor reactor;
-BTimer timer;
-BPending job;
-
-static void timer_handler (void *unused)
-{
-    printf("timer_handler %"PRIu64"\n", btime_gettime());
-    
-    BPending_Set(&job);
-    BReactor_SetTimer(&reactor, &timer);
-}
-
-static void job_handler (void *unused)
-{
-    printf("job_handler %"PRIu64"\n", btime_gettime());
-}
-
-int main ()
-{
-    BTime_Init();
-    
-    BReactor_EmscriptenInit(&reactor);
-    
-    BTimer_Init(&timer, 500, timer_handler, NULL);
-    BReactor_SetTimer(&reactor, &timer);
-    
-    BPending_Init(&job, BReactor_PendingGroup(&reactor), job_handler, NULL);
-    BPending_Set(&job);
-    
-    BReactor_EmscriptenSync(&reactor);
-    return 0;
-}
diff --git a/external/badvpn_dns/examples/fairqueue_test.c b/external/badvpn_dns/examples/fairqueue_test.c
deleted file mode 100644
index 482e086..0000000
--- a/external/badvpn_dns/examples/fairqueue_test.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/**
- * @file fairqueue_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-#include <stdio.h>
-#include <stddef.h>
-
-#include <misc/debug.h>
-#include <system/BReactor.h>
-#include <base/BLog.h>
-#include <system/BTime.h>
-#include <flow/PacketPassFairQueue.h>
-#include <examples/FastPacketSource.h>
-#include <examples/TimerPacketSink.h>
-
-#define OUTPUT_INTERVAL 0
-#define REMOVE_INTERVAL 1
-#define NUM_INPUTS 3
-
-BReactor reactor;
-TimerPacketSink sink;
-PacketPassFairQueue fq;
-PacketPassFairQueueFlow flows[NUM_INPUTS];
-FastPacketSource sources[NUM_INPUTS];
-char *data[] = {"0 data", "1 datadatadata", "2 datadatadatadatadata"};
-BTimer timer;
-int current_cancel;
-
-static void init_input (int i)
-{
-    PacketPassFairQueueFlow_Init(&flows[i], &fq);
-    FastPacketSource_Init(&sources[i], PacketPassFairQueueFlow_GetInput(&flows[i]), (uint8_t *)data[i], strlen(data[i]), BReactor_PendingGroup(&reactor));
-}
-
-static void free_input (int i)
-{
-    FastPacketSource_Free(&sources[i]);
-    PacketPassFairQueueFlow_Free(&flows[i]);
-}
-
-static void reset_input (void)
-{
-    PacketPassFairQueueFlow_AssertFree(&flows[current_cancel]);
-    
-    printf("removing %d\n", current_cancel);
-    
-    // remove flow
-    free_input(current_cancel);
-    
-    // init flow
-    init_input(current_cancel);
-    
-    // increment cancel
-    current_cancel = (current_cancel + 1) % NUM_INPUTS;
-    
-    // reset timer
-    BReactor_SetTimer(&reactor, &timer);
-}
-
-static void flow_handler_busy (void *user)
-{
-    PacketPassFairQueueFlow_AssertFree(&flows[current_cancel]);
-    
-    reset_input();
-}
-
-static void timer_handler (void *user)
-{
-    // if flow is busy, request cancel and wait for it
-    if (PacketPassFairQueueFlow_IsBusy(&flows[current_cancel])) {
-        printf("cancelling %d\n", current_cancel);
-        PacketPassFairQueueFlow_RequestCancel(&flows[current_cancel]);
-        PacketPassFairQueueFlow_SetBusyHandler(&flows[current_cancel], flow_handler_busy, NULL);
-        return;
-    }
-    
-    reset_input();
-}
-
-int main ()
-{
-    // initialize logging
-    BLog_InitStdout();
-    
-    // init time
-    BTime_Init();
-    
-    // initialize reactor
-    if (!BReactor_Init(&reactor)) {
-        DEBUG("BReactor_Init failed");
-        return 1;
-    }
-    
-    // initialize sink
-    TimerPacketSink_Init(&sink, &reactor, 500, OUTPUT_INTERVAL);
-    
-    // initialize queue
-    if (!PacketPassFairQueue_Init(&fq, TimerPacketSink_GetInput(&sink), BReactor_PendingGroup(&reactor), 1, 1)) {
-        DEBUG("PacketPassFairQueue_Init failed");
-        return 1;
-    }
-    
-    // initialize inputs
-    for (int i = 0; i < NUM_INPUTS; i++) {
-        init_input(i);
-    }
-    
-    // init cancel timer
-    BTimer_Init(&timer, REMOVE_INTERVAL, timer_handler, NULL);
-    BReactor_SetTimer(&reactor, &timer);
-    
-    // init cancel counter
-    current_cancel = 0;
-    
-    // run reactor
-    int ret = BReactor_Exec(&reactor);
-    BReactor_Free(&reactor);
-    return ret;
-}
diff --git a/external/badvpn_dns/examples/fairqueue_test2.c b/external/badvpn_dns/examples/fairqueue_test2.c
deleted file mode 100644
index 0fe9d34..0000000
--- a/external/badvpn_dns/examples/fairqueue_test2.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * @file fairqueue_test2.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-
-#include <misc/debug.h>
-#include <system/BReactor.h>
-#include <base/BLog.h>
-#include <system/BTime.h>
-#include <flow/PacketPassFairQueue.h>
-#include <examples/FastPacketSource.h>
-#include <examples/RandomPacketSink.h>
-
-#define SINK_TIMER 0
-
-int main ()
-{
-    // initialize logging
-    BLog_InitStdout();
-    
-    // init time
-    BTime_Init();
-    
-    // initialize reactor
-    BReactor reactor;
-    if (!BReactor_Init(&reactor)) {
-        DEBUG("BReactor_Init failed");
-        return 1;
-    }
-    
-    // initialize sink
-    RandomPacketSink sink;
-    RandomPacketSink_Init(&sink, &reactor, 500, SINK_TIMER);
-    
-    // initialize queue
-    PacketPassFairQueue fq;
-    if (!PacketPassFairQueue_Init(&fq, RandomPacketSink_GetInput(&sink), BReactor_PendingGroup(&reactor), 0, 1)) {
-        DEBUG("PacketPassFairQueue_Init failed");
-        return 1;
-    }
-    
-    // initialize source 1
-    PacketPassFairQueueFlow flow1;
-    PacketPassFairQueueFlow_Init(&flow1, &fq);
-    FastPacketSource source1;
-    char data1[] = "data1";
-    FastPacketSource_Init(&source1, PacketPassFairQueueFlow_GetInput(&flow1), (uint8_t *)data1, strlen(data1), BReactor_PendingGroup(&reactor));
-    
-    // initialize source 2
-    PacketPassFairQueueFlow flow2;
-    PacketPassFairQueueFlow_Init(&flow2, &fq);
-    FastPacketSource source2;
-    char data2[] = "data2data2";
-    FastPacketSource_Init(&source2, PacketPassFairQueueFlow_GetInput(&flow2), (uint8_t *)data2, strlen(data2), BReactor_PendingGroup(&reactor));
-    
-    // initialize source 3
-    PacketPassFairQueueFlow flow3;
-    PacketPassFairQueueFlow_Init(&flow3, &fq);
-    FastPacketSource source3;
-    char data3[] = "data3data3data3data3data3data3data3data3data3";
-    FastPacketSource_Init(&source3, PacketPassFairQueueFlow_GetInput(&flow3), (uint8_t *)data3, strlen(data3), BReactor_PendingGroup(&reactor));
-    
-    // run reactor
-    int ret = BReactor_Exec(&reactor);
-    BReactor_Free(&reactor);
-    return ret;
-}
diff --git a/external/badvpn_dns/examples/indexedlist_test.c b/external/badvpn_dns/examples/indexedlist_test.c
deleted file mode 100644
index d5282c0..0000000
--- a/external/badvpn_dns/examples/indexedlist_test.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * @file indexedlist_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <misc/debug.h>
-#include <misc/offset.h>
-#include <structure/IndexedList.h>
-
-IndexedList il;
-
-struct elem {
-    int value;
-    IndexedListNode node;
-};
-
-static void elem_insert (struct elem *e, int value, uint64_t index)
-{
-    e->value = value;
-    IndexedList_InsertAt(&il, &e->node, index);
-}
-
-static void remove_at (uint64_t index)
-{
-    IndexedListNode *n = IndexedList_GetAt(&il, index);
-    struct elem *e = UPPER_OBJECT(n, struct elem, node);
-    IndexedList_Remove(&il, &e->node);
-}
-
-static void print_list (void)
-{
-    for (uint64_t i = 0; i < IndexedList_Count(&il); i++) {
-        IndexedListNode *n = IndexedList_GetAt(&il, i);
-        struct elem *e = UPPER_OBJECT(n, struct elem, node);
-        printf("%d ", e->value);
-    }
-    printf("\n");
-}
-
-int main (int argc, char *argv[])
-{
-    IndexedList_Init(&il);
-    
-    struct elem arr[100];
-    
-    print_list();
-    
-    elem_insert(&arr[0], 1, 0);
-    print_list();
-    elem_insert(&arr[1], 2, 0);
-    print_list();
-    elem_insert(&arr[2], 3, 0);
-    print_list();
-    elem_insert(&arr[3], 4, 0);
-    print_list();
-    elem_insert(&arr[4], 5, 0);
-    print_list();
-    elem_insert(&arr[5], 6, 0);
-    print_list();
-    
-    elem_insert(&arr[6], 7, 1);
-    print_list();
-    
-    remove_at(0);
-    print_list();
-    
-    remove_at(5);
-    print_list();
-    
-    return 0;
-}
diff --git a/external/badvpn_dns/examples/ipaddr6_test.c b/external/badvpn_dns/examples/ipaddr6_test.c
deleted file mode 100644
index 7da486d..0000000
--- a/external/badvpn_dns/examples/ipaddr6_test.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/**
- * @file ipaddr6_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-#include <misc/debug.h>
-#include <misc/ipaddr6.h>
-
-#define PRINT_TEST(addr_bytes, string) \
-    { \
-        struct ipv6_addr addr = {addr_bytes}; \
-        char str[IPADDR6_PRINT_MAX]; \
-        ipaddr6_print_addr(addr, str); \
-        ASSERT_FORCE(!strcmp(str, (string))); \
-        struct ipv6_addr parsed_addr; \
-        int res = ipaddr6_parse_ipv6_addr_bin(str, strlen(str), &parsed_addr); \
-        ASSERT_FORCE(res); \
-        ASSERT_FORCE(!memcmp(parsed_addr.bytes, addr.bytes, 16)); \
-    }
-
-#define PARSE_TEST(string, addr_bytes) \
-    { \
-        struct ipv6_addr exp_addr = {addr_bytes}; \
-        struct ipv6_addr addr; \
-        int res = ipaddr6_parse_ipv6_addr_bin((string), strlen((string)), &addr); \
-        ASSERT_FORCE(res); \
-        ASSERT_FORCE(!memcmp(addr.bytes, exp_addr.bytes, 16)); \
-    }
-
-#define PARSE_FAIL_TEST(string) \
-    { \
-        struct ipv6_addr addr; \
-        int res = ipaddr6_parse_ipv6_addr_bin((string), strlen((string)), &addr); \
-        ASSERT_FORCE(!res); \
-    }
-
-#define MASK_TEST(mask_bytes, prefix) \
-    { \
-        struct ipv6_addr mask = {mask_bytes}; \
-        int parsed_prefix; \
-        int res = ipaddr6_ipv6_prefix_from_mask(mask, &parsed_prefix); \
-        ASSERT_FORCE(res); \
-        ASSERT_FORCE(parsed_prefix == (prefix)); \
-        struct ipv6_addr generated_mask; \
-        ipaddr6_ipv6_mask_from_prefix(parsed_prefix, &generated_mask); \
-        ASSERT_FORCE(!memcmp(generated_mask.bytes, mask.bytes, 16)); \
-    }
-
-#define PASS(...) __VA_ARGS__
-
-int main ()
-{
-    PRINT_TEST(PASS({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), "::1")
-    PRINT_TEST(PASS({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), "::")
-    PRINT_TEST(PASS({0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}),"2001:db8::1")
-    PRINT_TEST(PASS({0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01}), "2001:db8::2:1")
-    PRINT_TEST(PASS({0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01}), "2001:db8:0:1:1:1:1:1")
-    PRINT_TEST(PASS({0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01}), "2001:db8:0:1:1:1:1:1")
-    PRINT_TEST(PASS({0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}), "2001:db8::1:0:0:1")
-    
-    PARSE_TEST("::", PASS({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}))
-    PARSE_TEST("::1", PASS({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}))
-    PARSE_TEST("::abcd", PASS({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0xcd}))
-    PARSE_TEST("::0123:abcd", PASS({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0xab, 0xcd}))
-    PARSE_TEST("abcd::", PASS({0xab, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}))
-    PARSE_TEST("abcd:0123::", PASS({0xab, 0xcd, 0x01, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}))
-    PARSE_TEST("1::2", PASS({0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}))
-    PARSE_TEST("abcd:0123::3210:dcba", PASS({0xab, 0xcd, 0x01, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x10, 0xdc, 0xba}))
-    PARSE_TEST("4567:abcd:0123::3210:dcba", PASS({0x45, 0x67, 0xab, 0xcd, 0x01, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x10, 0xdc, 0xba}))
-    PARSE_TEST("4567:abcd:0123:1111:2222:3333:3210::", PASS({0x45, 0x67, 0xab, 0xcd, 0x01, 0x23, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x32, 0x10, 0x00, 0x00}))
-    PARSE_TEST("::4567:abcd:0123:1111:2222:3333:3210", PASS({0x00, 0x00, 0x45, 0x67, 0xab, 0xcd, 0x01, 0x23, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x32, 0x10}))
-    PARSE_TEST("4567:abcd:0123:1111:2222:3333:3210:dcba", PASS({0x45, 0x67, 0xab, 0xcd, 0x01, 0x23, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x32, 0x10, 0xdc, 0xba}))
-    PARSE_TEST("04567:000abcd:00000123:01111:2222:03333:0003210:0dcba", PASS({0x45, 0x67, 0xab, 0xcd, 0x01, 0x23, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x32, 0x10, 0xdc, 0xba}))
-    PARSE_TEST("::1.2.3.4", PASS({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04}))
-    PARSE_TEST("ff::1.2.3.4", PASS({0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04}))
-    PARSE_TEST("ff::0.2.3.4", PASS({0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x04}))
-    PARSE_TEST("1:2:3:4:5:6:1.2.3.4", PASS({0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x01, 0x02, 0x03, 0x04}))
-    PARSE_TEST("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255", PASS({0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}))
-    PARSE_TEST("1::fffa:1.2.3.4", PASS({0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfa, 0x01, 0x02, 0x03, 0x04}))
-    PARSE_TEST("1::fffa:0.0.0.0", PASS({0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00}))
-    
-    PARSE_FAIL_TEST("")
-    PARSE_FAIL_TEST(":")
-    PARSE_FAIL_TEST("a")
-    PARSE_FAIL_TEST("a:b")
-    PARSE_FAIL_TEST(":b")
-    PARSE_FAIL_TEST("b:")
-    PARSE_FAIL_TEST("1:2:3:4:5:6:7")
-    PARSE_FAIL_TEST(":1:2:3:4:5:6:7")
-    PARSE_FAIL_TEST("1:2:3:4:5:6:7:")
-    PARSE_FAIL_TEST(":::")
-    PARSE_FAIL_TEST("::a::")
-    PARSE_FAIL_TEST("::a::b")
-    PARSE_FAIL_TEST("c::a::b")
-    PARSE_FAIL_TEST("c::a::")
-    PARSE_FAIL_TEST("10000::")
-    PARSE_FAIL_TEST("1:2:3:4:5:6:7:8:9")
-    PARSE_FAIL_TEST("1:2:3:4::5:6:7:8:9")
-    PARSE_FAIL_TEST("::1:2:3:4:5:6:7:8:9")
-    PARSE_FAIL_TEST("1:2:3:4:5:6:7:8:9::")
-    PARSE_FAIL_TEST("a::b:")
-    PARSE_FAIL_TEST(":a::b")
-    PARSE_FAIL_TEST("::g")
-    PARSE_FAIL_TEST("::1.2")
-    PARSE_FAIL_TEST("::1.2.3.4.5")
-    PARSE_FAIL_TEST("::01.2.3.4")
-    PARSE_FAIL_TEST("::1.2.3.04")
-    PARSE_FAIL_TEST("::1.2.3.256")
-    PARSE_FAIL_TEST("1.2.3.4")
-    PARSE_FAIL_TEST("::8259.2.473.256")
-    PARSE_FAIL_TEST("1:2:3:4:5:6:7:1.2.3.4")
-    PARSE_FAIL_TEST("1:2:3:4:5:1.2.3.4")
-    PARSE_FAIL_TEST("::1.2.3.4::")
-    PARSE_FAIL_TEST("::1.2.3.4:1")
-    PARSE_FAIL_TEST("localhost6")
-    
-    MASK_TEST(PASS({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 0)
-    MASK_TEST(PASS({0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 1)
-    MASK_TEST(PASS({0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 2)
-    MASK_TEST(PASS({0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 3)
-    MASK_TEST(PASS({0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 4)
-    MASK_TEST(PASS({0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 5)
-    MASK_TEST(PASS({0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 6)
-    MASK_TEST(PASS({0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 7)
-    MASK_TEST(PASS({0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 8)
-    
-    MASK_TEST(PASS({0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 9)
-    MASK_TEST(PASS({0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 10)
-    MASK_TEST(PASS({0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 11)
-    MASK_TEST(PASS({0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 12)
-    MASK_TEST(PASS({0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 13)
-    MASK_TEST(PASS({0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 14)
-    MASK_TEST(PASS({0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 15)
-    MASK_TEST(PASS({0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}), 16)
-    
-    MASK_TEST(PASS({0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE}), 127)
-    MASK_TEST(PASS({0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}), 128)
-    
-    return 0;
-}
diff --git a/external/badvpn_dns/examples/ncd_parser_test.c b/external/badvpn_dns/examples/ncd_parser_test.c
deleted file mode 100644
index ac913b5..0000000
--- a/external/badvpn_dns/examples/ncd_parser_test.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/**
- * @file ncd_parser_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-#include <misc/debug.h>
-#include <misc/expstring.h>
-#include <base/BLog.h>
-#include <ncd/NCDConfigParser.h>
-#include <ncd/NCDValGenerator.h>
-#include <ncd/NCDSugar.h>
-
-static int generate_val (NCDValue *value, ExpString *out_str)
-{
-    switch (NCDValue_Type(value)) {
-        case NCDVALUE_STRING: {
-            const char *str = NCDValue_StringValue(value);
-            size_t len = NCDValue_StringLength(value);
-            
-            if (!ExpString_AppendChar(out_str, '"')) {
-                goto fail;
-            }
-            
-            for (size_t i = 0; i < len; i++) {
-                if (str[i] == '\0') {
-                    char buf[5];
-                    snprintf(buf, sizeof(buf), "\\x%02"PRIx8, (uint8_t)str[i]);
-                    
-                    if (!ExpString_Append(out_str, buf)) {
-                        goto fail;
-                    }
-                    
-                    continue;
-                }
-                
-                if (str[i] == '"' || str[i] == '\\') {
-                    if (!ExpString_AppendChar(out_str, '\\')) {
-                        goto fail;
-                    }
-                }
-                
-                if (!ExpString_AppendChar(out_str, str[i])) {
-                    goto fail;
-                }
-            }
-            
-            if (!ExpString_AppendChar(out_str, '"')) {
-                goto fail;
-            }
-        } break;
-        
-        case NCDVALUE_LIST: {
-            if (!ExpString_AppendChar(out_str, '{')) {
-                goto fail;
-            }
-            
-            int is_first = 1;
-            
-            for (NCDValue *e = NCDValue_ListFirst(value); e; e = NCDValue_ListNext(value, e)) {
-                if (!is_first) {
-                    if (!ExpString_Append(out_str, ", ")) {
-                        goto fail;
-                    }
-                }
-                
-                if (!generate_val(e, out_str)) {
-                    goto fail;
-                }
-                
-                is_first = 0;
-            }
-            
-            if (!ExpString_AppendChar(out_str, '}')) {
-                goto fail;
-            }
-        } break;
-        
-        case NCDVALUE_MAP: {
-            if (!ExpString_AppendChar(out_str, '[')) {
-                goto fail;
-            }
-            
-            int is_first = 1;
-            
-            for (NCDValue *ekey = NCDValue_MapFirstKey(value); ekey; ekey = NCDValue_MapNextKey(value, ekey)) {
-                NCDValue *eval = NCDValue_MapKeyValue(value, ekey);
-                
-                if (!is_first) {
-                    if (!ExpString_Append(out_str, ", ")) {
-                        goto fail;
-                    }
-                }
-                
-                if (!generate_val(ekey, out_str)) {
-                    goto fail;
-                }
-                
-                if (!ExpString_AppendChar(out_str, ':')) {
-                    goto fail;
-                }
-                
-                if (!generate_val(eval, out_str)) {
-                    goto fail;
-                }
-                
-                is_first = 0;
-            }
-            
-            if (!ExpString_AppendChar(out_str, ']')) {
-                goto fail;
-            }
-        } break;
-        
-        default: ASSERT(0);
-    }
-    
-    return 1;
-    
-fail:
-    return 0;
-}
-
-static void print_indent (unsigned int indent)
-{
-    while (indent > 0) {
-        printf("  ");
-        indent--;
-    }
-}
-
-static void print_value (NCDValue *v, unsigned int indent)
-{
-    ExpString estr;
-    if (!ExpString_Init(&estr)) {
-        DEBUG("ExpString_Init failed");
-        exit(1);
-    }
-    
-    if (!generate_val(v, &estr)) {
-        DEBUG("generate_val failed");
-        exit(1);
-    }
-    
-    print_indent(indent);
-    printf("%s\n", ExpString_Get(&estr));
-    
-    ExpString_Free(&estr);
-}
-
-static void print_block (NCDBlock *block, unsigned int indent)
-{
-    for (NCDStatement *st = NCDBlock_FirstStatement(block); st; st = NCDBlock_NextStatement(block, st)) {
-        const char *name = NCDStatement_Name(st) ? NCDStatement_Name(st) : "";
-        
-        switch (NCDStatement_Type(st)) {
-            case NCDSTATEMENT_REG: {
-                const char *objname = NCDStatement_RegObjName(st) ? NCDStatement_RegObjName(st) : "";
-                const char *cmdname = NCDStatement_RegCmdName(st);
-                
-                print_indent(indent);
-                printf("reg name=%s objname=%s cmdname=%s args:\n", name, objname, cmdname);
-                
-                print_value(NCDStatement_RegArgs(st), indent + 2);
-            } break;
-            
-            case NCDSTATEMENT_IF: {
-                print_indent(indent);
-                printf("if name=%s\n", name);
-                
-                NCDIfBlock *ifb = NCDStatement_IfBlock(st);
-                
-                for (NCDIf *ifc = NCDIfBlock_FirstIf(ifb); ifc; ifc = NCDIfBlock_NextIf(ifb, ifc)) {
-                    print_indent(indent + 2);
-                    printf("if\n");
-                    
-                    print_value(NCDIf_Cond(ifc), indent + 4);
-                    
-                    print_indent(indent + 2);
-                    printf("then\n");
-                    
-                    print_block(NCDIf_Block(ifc), indent + 4);
-                }
-                
-                if (NCDStatement_IfElse(st)) {
-                    print_indent(indent + 2);
-                    printf("else\n");
-                    
-                    print_block(NCDStatement_IfElse(st), indent + 4);
-                }
-            } break;
-            
-            case NCDSTATEMENT_FOREACH: {
-                const char *name1 = NCDStatement_ForeachName1(st);
-                const char *name2 = NCDStatement_ForeachName2(st) ? NCDStatement_ForeachName2(st) : "";
-                
-                print_indent(indent);
-                printf("foreach name=%s name1=%s name2=%s\n", name, name1, name2);
-                
-                print_block(NCDStatement_ForeachBlock(st), indent + 2);
-            } break;
-            
-            default: ASSERT(0);
-        }
-    }
-}
-
-int main (int argc, char **argv)
-{
-    int res = 1;
-    
-    if (argc != 3) {
-        printf("Usage: %s <desugar=0/1> <string>\n", (argc > 0 ? argv[0] : ""));
-        goto fail0;
-    }
-    
-    int desugar = atoi(argv[1]);
-    char *text = argv[2];
-    
-    BLog_InitStdout();
-    
-    // parse
-    NCDProgram prog;
-    if (!NCDConfigParser_Parse(text, strlen(text), &prog)) {
-        DEBUG("NCDConfigParser_Parse failed");
-        goto fail1;
-    }
-    
-    // desugar
-    if (desugar) {
-        if (!NCDSugar_Desugar(&prog)) {
-            DEBUG("NCDSugar_Desugar failed");
-            goto fail2;
-        }
-    }
-    
-    // print
-    for (NCDProgramElem *elem = NCDProgram_FirstElem(&prog); elem; elem = NCDProgram_NextElem(&prog, elem)) {
-        switch (NCDProgramElem_Type(elem)) {
-            case NCDPROGRAMELEM_PROCESS: {
-                NCDProcess *p = NCDProgramElem_Process(elem);
-                printf("process name=%s is_template=%d\n", NCDProcess_Name(p), NCDProcess_IsTemplate(p));
-                print_block(NCDProcess_Block(p), 2);
-            } break;
-            
-            case NCDPROGRAMELEM_INCLUDE: {
-                printf("include path=%s\n", NCDProgramElem_IncludePathData(elem));
-            } break;
-            
-            case NCDPROGRAMELEM_INCLUDE_GUARD: {
-                printf("include_guard id=%s\n", NCDProgramElem_IncludeGuardIdData(elem));
-            } break;
-            
-            default: ASSERT(0);
-        }
-    }
-    
-    res = 0;
-fail2:
-    NCDProgram_Free(&prog);
-fail1:
-    BLog_Free();
-fail0:
-    return res;
-}
diff --git a/external/badvpn_dns/examples/ncd_tokenizer_test.c b/external/badvpn_dns/examples/ncd_tokenizer_test.c
deleted file mode 100644
index 84f90eb..0000000
--- a/external/badvpn_dns/examples/ncd_tokenizer_test.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/**
- * @file ncd_tokenizer_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <misc/debug.h>
-#include <base/BLog.h>
-#include <ncd/NCDConfigTokenizer.h>
-
-int error;
-
-static int tokenizer_output (void *user, int token, char *value, size_t value_len, size_t line, size_t line_char)
-{
-    if (token == NCD_ERROR) {
-        printf("line %zu, character %zu: tokenizer error\n", line, line_char);
-        error = 1;
-        return 0;
-    }
-    
-    switch (token) {
-        case NCD_EOF:
-            printf("eof\n");
-            break;
-        case NCD_TOKEN_CURLY_OPEN:
-            printf("curly_open\n");
-            break;
-        case NCD_TOKEN_CURLY_CLOSE:
-            printf("curly_close\n");
-            break;
-        case NCD_TOKEN_ROUND_OPEN:
-            printf("round_open\n");
-            break;
-        case NCD_TOKEN_ROUND_CLOSE:
-            printf("round_close\n");
-            break;
-        case NCD_TOKEN_SEMICOLON:
-            printf("semicolon\n");
-            break;
-        case NCD_TOKEN_DOT:
-            printf("dot\n");
-            break;
-        case NCD_TOKEN_COMMA:
-            printf("comma\n");
-            break;
-        case NCD_TOKEN_PROCESS:
-            printf("process\n");
-            break;
-        case NCD_TOKEN_NAME:
-            printf("name %s\n", value);
-            free(value);
-            break;
-        case NCD_TOKEN_STRING:
-            printf("string %s\n", value);
-            free(value);
-            break;
-        case NCD_TOKEN_ARROW:
-            printf("arrow\n");
-            break;
-        case NCD_TOKEN_TEMPLATE:
-            printf("template\n");
-            break;
-        case NCD_TOKEN_COLON:
-            printf("colon\n");
-            break;
-        case NCD_TOKEN_BRACKET_OPEN:
-            printf("bracket open\n");
-            break;
-        case NCD_TOKEN_BRACKET_CLOSE:
-            printf("bracket close\n");
-            break;
-        case NCD_TOKEN_IF:
-            printf("if\n");
-            break;
-        case NCD_TOKEN_ELIF:
-            printf("elif\n");
-            break;
-        case NCD_TOKEN_ELSE:
-            printf("else\n");
-            break;
-        case NCD_TOKEN_FOREACH:
-            printf("foreach\n");
-            break;
-        case NCD_TOKEN_AS:
-            printf("as\n");
-            break;
-        case NCD_TOKEN_INCLUDE:
-            printf("include\n");
-            break;
-        case NCD_TOKEN_INCLUDE_GUARD:
-            printf("include_guard\n");
-            break;
-        default:
-            ASSERT(0);
-    }
-    
-    return 1;
-}
-
-int main (int argc, char **argv)
-{
-    if (argc < 1) {
-        return 1;
-    }
-    
-    if (argc != 2) {
-        printf("Usage: %s <string>\n", argv[0]);
-        return 1;
-    }
-    
-    BLog_InitStdout();
-    
-    error = 0;
-    
-    NCDConfigTokenizer_Tokenize(argv[1], strlen(argv[1]), tokenizer_output, NULL);
-    
-    if (error) {
-        return 1;
-    }
-    
-    return 0;
-}
diff --git a/external/badvpn_dns/examples/ncd_value_parser_test.c b/external/badvpn_dns/examples/ncd_value_parser_test.c
deleted file mode 100644
index cf1915d..0000000
--- a/external/badvpn_dns/examples/ncd_value_parser_test.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * @file ncd_value_parser_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <misc/debug.h>
-#include <base/BLog.h>
-#include <ncd/NCDValParser.h>
-#include <ncd/NCDValGenerator.h>
-
-int main (int argc, char *argv[])
-{
-    int res = 1;
-    
-    if (argc != 2) {
-        printf("Usage: %s <string>\n", (argc > 0 ? argv[0] : ""));
-        goto fail0;
-    }
-    
-    BLog_InitStdout();
-    
-    NCDValMem mem;
-    NCDValMem_Init(&mem);
-    
-    // parse
-    NCDValRef val;
-    if (!NCDValParser_Parse(argv[1], strlen(argv[1]), &mem, &val)) {
-        DEBUG("NCDValParser_Parse failed");
-        goto fail1;
-    }
-    
-    // generate value string
-    char *str = NCDValGenerator_Generate(val);
-    if (!str) {
-        DEBUG("NCDValGenerator_Generate failed");
-        goto fail1;
-    }
-    
-    // print value string
-    printf("%s\n", str);
-    
-    res = 0;
-    
-    free(str);
-fail1:
-    NCDValMem_Free(&mem);
-    BLog_Free();
-fail0:
-    return res;
-}
diff --git a/external/badvpn_dns/examples/ncdinterfacemonitor_test.c b/external/badvpn_dns/examples/ncdinterfacemonitor_test.c
deleted file mode 100644
index 167f1bd..0000000
--- a/external/badvpn_dns/examples/ncdinterfacemonitor_test.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/**
- * @file ncdinterfacemonitor_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-#include <inttypes.h>
-#include <stdio.h>
-
-#include <misc/get_iface_info.h>
-#include <misc/ipaddr6.h>
-#include <misc/debug.h>
-#include <base/BLog.h>
-#include <system/BTime.h>
-#include <system/BReactor.h>
-#include <system/BSignal.h>
-#include <ncd/extra/NCDInterfaceMonitor.h>
-
-BReactor reactor;
-NCDInterfaceMonitor monitor;
-
-static void signal_handler (void *user);
-static void monitor_handler (void *unused, struct NCDInterfaceMonitor_event event);
-static void monitor_handler_error (void *unused);
-
-int main (int argc, char **argv)
-{
-    int ret = 1;
-    
-    if (argc != 2) {
-        fprintf(stderr, "Usage: %s <interface>\n", (argc > 0 ? argv[0] : ""));
-        goto fail0;
-    }
-    
-    int ifindex;
-    if (!badvpn_get_iface_info(argv[1], NULL, NULL, &ifindex)) {
-        DEBUG("get_iface_info failed");
-        goto fail0;
-    }
-    
-    BTime_Init();
-    
-    BLog_InitStdout();
-    
-    if (!BNetwork_GlobalInit()) {
-        DEBUG("BNetwork_GlobalInit failed");
-        goto fail1;
-    }
-    
-    if (!BReactor_Init(&reactor)) {
-        DEBUG("BReactor_Init failed");
-        goto fail1;
-    }
-    
-    if (!BSignal_Init(&reactor, signal_handler, NULL)) {
-        DEBUG("BSignal_Init failed");
-        goto fail2;
-    }
-    
-    int watch_flags = NCDIFMONITOR_WATCH_LINK|NCDIFMONITOR_WATCH_IPV4_ADDR|NCDIFMONITOR_WATCH_IPV6_ADDR;
-    
-    if (!NCDInterfaceMonitor_Init(&monitor, ifindex, watch_flags, &reactor, NULL, monitor_handler, monitor_handler_error)) {
-        DEBUG("NCDInterfaceMonitor_Init failed");
-        goto fail3;
-    }
-    
-    ret = BReactor_Exec(&reactor);
-    
-    NCDInterfaceMonitor_Free(&monitor);
-fail3:
-    BSignal_Finish();
-fail2:
-    BReactor_Free(&reactor);
-fail1:
-    BLog_Free();
-fail0:
-    DebugObjectGlobal_Finish();
-    
-    return ret;
-}
-
-void signal_handler (void *user)
-{
-    DEBUG("termination requested");
-    
-    BReactor_Quit(&reactor, 1);
-}
-
-void monitor_handler (void *unused, struct NCDInterfaceMonitor_event event)
-{
-    switch (event.event) {
-        case NCDIFMONITOR_EVENT_LINK_UP:
-        case NCDIFMONITOR_EVENT_LINK_DOWN: {
-            const char *type = (event.event == NCDIFMONITOR_EVENT_LINK_UP) ? "up" : "down";
-            printf("link %s\n", type);
-        } break;
-        
-        case NCDIFMONITOR_EVENT_IPV4_ADDR_ADDED:
-        case NCDIFMONITOR_EVENT_IPV4_ADDR_REMOVED: {
-            const char *type = (event.event == NCDIFMONITOR_EVENT_IPV4_ADDR_ADDED) ? "added" : "removed";
-            uint8_t *addr = (uint8_t *)&event.u.ipv4_addr.addr;
-            printf("ipv4 addr %s %d.%d.%d.%d/%d\n", type, (int)addr[0], (int)addr[1], (int)addr[2], (int)addr[3], event.u.ipv4_addr.addr.prefix);
-        } break;
-        
-        case NCDIFMONITOR_EVENT_IPV6_ADDR_ADDED:
-        case NCDIFMONITOR_EVENT_IPV6_ADDR_REMOVED: {
-            const char *type = (event.event == NCDIFMONITOR_EVENT_IPV6_ADDR_ADDED) ? "added" : "removed";
-            
-            char str[IPADDR6_PRINT_MAX];
-            ipaddr6_print_addr(event.u.ipv6_addr.addr.addr, str);
-            
-            int dynamic = !!(event.u.ipv6_addr.addr_flags & NCDIFMONITOR_ADDR_FLAG_DYNAMIC);
-            
-            printf("ipv6 addr %s %s/%d scope=%"PRIu8" dynamic=%d\n", type, str, event.u.ipv6_addr.addr.prefix, event.u.ipv6_addr.scope, dynamic);
-        } break;
-        
-        default: ASSERT(0);
-    }
-}
-
-void monitor_handler_error (void *unused)
-{
-    DEBUG("monitor error");
-    
-    BReactor_Quit(&reactor, 1);
-}
diff --git a/external/badvpn_dns/examples/ncdudevmanager_test.c b/external/badvpn_dns/examples/ncdudevmanager_test.c
deleted file mode 100644
index 9bbb3fe..0000000
--- a/external/badvpn_dns/examples/ncdudevmanager_test.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/**
- * @file ncdudevmanager_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <misc/debug.h>
-#include <system/BTime.h>
-#include <base/BLog.h>
-#include <system/BReactor.h>
-#include <system/BUnixSignal.h>
-#include <system/BProcess.h>
-#include <system/BNetwork.h>
-#include <udevmonitor/NCDUdevManager.h>
-
-BReactor reactor;
-BUnixSignal usignal;
-BProcessManager manager;
-NCDUdevManager umanager;
-NCDUdevClient client;
-
-static void signal_handler (void *user, int signo);
-static void client_handler (void *unused, char *devpath, int have_map, BStringMap map);
-
-int main (int argc, char **argv)
-{
-    if (!(argc == 1 || (argc == 2 && !strcmp(argv[1], "--no-udev")))) {
-        fprintf(stderr, "Usage: %s [--no-udev]\n", (argc > 0 ? argv[0] : NULL));
-        goto fail0;
-    }
-    
-    int no_udev = (argc == 2);
-    
-    if (!BNetwork_GlobalInit()) {
-        DEBUG("BNetwork_GlobalInit failed");
-        goto fail0;
-    }
-    
-    BTime_Init();
-    
-    BLog_InitStdout();
-    
-    if (!BReactor_Init(&reactor)) {
-        DEBUG("BReactor_Init failed");
-        goto fail1;
-    }
-    
-    sigset_t set;
-    sigemptyset(&set);
-    sigaddset(&set, SIGINT);
-    sigaddset(&set, SIGTERM);
-    sigaddset(&set, SIGHUP);
-    if (!BUnixSignal_Init(&usignal, &reactor, set, signal_handler, NULL)) {
-        fprintf(stderr, "BUnixSignal_Init failed\n");
-        goto fail2;
-    }
-    
-    if (!BProcessManager_Init(&manager, &reactor)) {
-        DEBUG("BProcessManager_Init failed");
-        goto fail3;
-    }
-    
-    NCDUdevManager_Init(&umanager, no_udev, &reactor, &manager);
-    
-    NCDUdevClient_Init(&client, &umanager, NULL, client_handler);
-    
-    BReactor_Exec(&reactor);
-    
-    NCDUdevClient_Free(&client);
-    
-    NCDUdevManager_Free(&umanager);
-    
-    BProcessManager_Free(&manager);
-fail3:
-    BUnixSignal_Free(&usignal, 0);
-fail2:
-    BReactor_Free(&reactor);
-fail1:
-    BLog_Free();
-fail0:
-    DebugObjectGlobal_Finish();
-    
-    return 1;
-}
-
-static void signal_handler (void *user, int signo)
-{
-    if (signo == SIGHUP) {
-        fprintf(stderr, "received SIGHUP, restarting client\n");
-        
-        NCDUdevClient_Free(&client);
-        NCDUdevClient_Init(&client, &umanager, NULL, client_handler);
-    } else {
-        fprintf(stderr, "received %s, exiting\n", (signo == SIGINT ? "SIGINT" : "SIGTERM"));
-        
-        // exit event loop
-        BReactor_Quit(&reactor, 1);
-    }
-}
-
-void client_handler (void *unused, char *devpath, int have_map, BStringMap map)
-{
-    printf("event %s\n", devpath);
-    
-    if (!have_map) {
-        printf("  no map\n");
-    } else {
-        printf("  map:\n");
-        
-        const char *name = BStringMap_First(&map);
-        while (name) {
-            printf("    %s=%s\n", name, BStringMap_Get(&map, name));
-            name = BStringMap_Next(&map, name);
-        }
-    }
-    
-    const BStringMap *cache_map = NCDUdevManager_Query(&umanager, devpath);
-    if (!cache_map) {
-        printf("  no cache\n");
-    } else {
-        printf("  cache:\n");
-        
-        const char *name = BStringMap_First(cache_map);
-        while (name) {
-            printf("    %s=%s\n", name, BStringMap_Get(cache_map, name));
-            name = BStringMap_Next(cache_map, name);
-        }
-    }
-    
-    if (have_map) {
-        BStringMap_Free(&map);
-    }
-    free(devpath);
-}
diff --git a/external/badvpn_dns/examples/ncdudevmonitor_test.c b/external/badvpn_dns/examples/ncdudevmonitor_test.c
deleted file mode 100644
index 94b4f6f..0000000
--- a/external/badvpn_dns/examples/ncdudevmonitor_test.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * @file ncdudevmonitor_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-
-#include <system/BTime.h>
-#include <base/BLog.h>
-#include <system/BReactor.h>
-#include <system/BSignal.h>
-#include <system/BProcess.h>
-#include <system/BNetwork.h>
-#include <udevmonitor/NCDUdevMonitor.h>
-
-BReactor reactor;
-BProcessManager manager;
-NCDUdevMonitor monitor;
-
-static void signal_handler (void *user);
-static void monitor_handler_event (void *unused);
-static void monitor_handler_error (void *unused, int is_error);
-
-int main (int argc, char **argv)
-{
-    int ret = 1;
-    
-    if (argc < 2 || (strcmp(argv[1], "monitor_udev") && strcmp(argv[1], "monitor_kernel") && strcmp(argv[1], "info"))) {
-        fprintf(stderr, "Usage: %s <monitor_udev/monitor_kernel/info>\n", (argc > 0 ? argv[0] : NULL));
-        goto fail0;
-    }
-    
-    int mode;
-    if (!strcmp(argv[1], "monitor_udev")) {
-        mode = NCDUDEVMONITOR_MODE_MONITOR_UDEV;
-    } else if (!strcmp(argv[1], "monitor_kernel")) {
-        mode = NCDUDEVMONITOR_MODE_MONITOR_KERNEL;
-    } else {
-        mode = NCDUDEVMONITOR_MODE_INFO;
-    }
-    
-    if (!BNetwork_GlobalInit()) {
-        DEBUG("BNetwork_GlobalInit failed");
-        goto fail0;
-    }
-    
-    BTime_Init();
-    
-    BLog_InitStdout();
-    
-    if (!BReactor_Init(&reactor)) {
-        DEBUG("BReactor_Init failed");
-        goto fail1;
-    }
-    
-    if (!BSignal_Init(&reactor, signal_handler, NULL)) {
-        DEBUG("BSignal_Init failed");
-        goto fail2;
-    }
-    
-    if (!BProcessManager_Init(&manager, &reactor)) {
-        DEBUG("BProcessManager_Init failed");
-        goto fail3;
-    }
-    
-    if (!NCDUdevMonitor_Init(&monitor, &reactor, &manager, mode, NULL,
-        monitor_handler_event,
-        monitor_handler_error
-    )) {
-        DEBUG("NCDUdevMonitor_Init failed");
-        goto fail4;
-    }
-    
-    ret = BReactor_Exec(&reactor);
-    
-    NCDUdevMonitor_Free(&monitor);
-fail4:
-    BProcessManager_Free(&manager);
-fail3:
-    BSignal_Finish();
-fail2:
-    BReactor_Free(&reactor);
-fail1:
-    BLog_Free();
-fail0:
-    DebugObjectGlobal_Finish();
-    
-    return ret;
-}
-
-void signal_handler (void *user)
-{
-    DEBUG("termination requested");
-    
-    BReactor_Quit(&reactor, 1);
-}
-
-void monitor_handler_event (void *unused)
-{
-    // accept event
-    NCDUdevMonitor_Done(&monitor);
-    
-    if (NCDUdevMonitor_IsReadyEvent(&monitor)) {
-        printf("ready\n");
-        return;
-    }
-    
-    printf("event\n");
-    
-    int num_props = NCDUdevMonitor_GetNumProperties(&monitor);
-    for (int i = 0; i < num_props; i++) {
-        const char *name;
-        const char *value;
-        NCDUdevMonitor_GetProperty(&monitor, i, &name, &value);
-        printf("  %s=%s\n", name, value);
-    }
-}
-
-void monitor_handler_error (void *unused, int is_error)
-{
-    if (is_error) {
-        DEBUG("monitor error");
-    } else {
-        DEBUG("monitor finished");
-    }
-    
-    BReactor_Quit(&reactor, (is_error ? 1 : 0));
-}
diff --git a/external/badvpn_dns/examples/ncdval_test.c b/external/badvpn_dns/examples/ncdval_test.c
deleted file mode 100644
index 6933ed0..0000000
--- a/external/badvpn_dns/examples/ncdval_test.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/**
- * @file ncdval_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-
-#include <ncd/NCDVal.h>
-#include <ncd/NCDStringIndex.h>
-#include <ncd/static_strings.h>
-#include <base/BLog.h>
-#include <misc/debug.h>
-#include <misc/balloc.h>
-#include <misc/offset.h>
-
-#define FORCE(cmd) if (!(cmd)) { fprintf(stderr, "failed\n"); exit(1); }
-
-struct composed_string {
-    BRefTarget ref_target;
-    size_t length;
-    size_t chunk_size;
-    char **chunks;
-};
-
-static void composed_string_ref_target_func_release (BRefTarget *ref_target)
-{
-    struct composed_string *cs = UPPER_OBJECT(ref_target, struct composed_string, ref_target);
-    
-    size_t num_chunks = cs->length / cs->chunk_size;
-    if (cs->length % cs->chunk_size) {
-        num_chunks++;
-    }
-    
-    for (size_t i = 0; i < num_chunks; i++) {
-        BFree(cs->chunks[i]);
-    }
-    
-    BFree(cs->chunks);
-    BFree(cs);
-}
-
-static void composed_string_func_getptr (void *user, size_t offset, const char **out_data, size_t *out_length)
-{
-    struct composed_string *cs = user;
-    ASSERT(offset < cs->length)
-    
-    *out_data = cs->chunks[offset / cs->chunk_size] + (offset % cs->chunk_size);
-    *out_length = cs->chunk_size - (offset % cs->chunk_size);
-}
-
-static NCDValRef build_composed_string (NCDValMem *mem, const char *data, size_t length, size_t chunk_size)
-{
-    ASSERT(chunk_size > 0)
-    
-    struct composed_string *cs = BAlloc(sizeof(*cs));
-    if (!cs) {
-        goto fail0;
-    }
-    
-    cs->length = length;
-    cs->chunk_size = chunk_size;
-    
-    size_t num_chunks = cs->length / cs->chunk_size;
-    if (cs->length % cs->chunk_size) {
-        num_chunks++;
-    }
-    
-    cs->chunks = BAllocArray(num_chunks, sizeof(cs->chunks[0]));
-    if (!cs->chunk_size) {
-        goto fail1;
-    }
-    
-    size_t i;
-    for (i = 0; i < num_chunks; i++) {
-        cs->chunks[i] = BAlloc(cs->chunk_size);
-        if (!cs->chunks[i]) {
-            goto fail2;
-        }
-        
-        size_t to_copy = length;
-        if (to_copy > cs->chunk_size) {
-            to_copy = cs->chunk_size;
-        }
-        
-        memcpy(cs->chunks[i], data, to_copy);
-        data += to_copy;
-        length -= to_copy;
-    }
-    
-    BRefTarget_Init(&cs->ref_target, composed_string_ref_target_func_release);
-    
-    NCDValComposedStringResource resource;
-    resource.func_getptr = composed_string_func_getptr;
-    resource.user = cs;
-    resource.ref_target = &cs->ref_target;
-    
-    NCDValRef val = NCDVal_NewComposedString(mem, resource, 0, cs->length);
-    BRefTarget_Deref(&cs->ref_target);
-    return val;
-    
-fail2:
-    while (i-- > 0) {
-        BFree(cs->chunks[i]);
-    }
-    BFree(cs->chunks);
-fail1:
-    BFree(cs);
-fail0:
-    return NCDVal_NewInvalid();
-}
-
-static void test_string (NCDValRef str, const char *data, size_t length)
-{
-    FORCE( !NCDVal_IsInvalid(str) )
-    FORCE( NCDVal_IsString(str) )
-    FORCE( NCDVal_StringLength(str) == length )
-    FORCE( NCDVal_StringHasNulls(str) == !!memchr(data, '\0', length) )
-    FORCE( NCDVal_IsStringNoNulls(str) == !memchr(data, '\0', length) )
-    FORCE( NCDVal_StringRegionEquals(str, 0, length, data) )
-    
-    b_cstring cstr = NCDVal_StringCstring(str);
-    
-    for (size_t i = 0; i < length; i++) {
-        size_t chunk_length;
-        const char *chunk_data = b_cstring_get(cstr, i, length - i, &chunk_length);
-        
-        FORCE( chunk_length > 0 )
-        FORCE( chunk_length <= length - i )
-        FORCE( !memcmp(chunk_data, data + i, chunk_length) )
-        FORCE( NCDVal_StringRegionEquals(str, i, chunk_length, data + i) )
-        FORCE( b_cstring_memcmp(cstr, b_cstring_make_buf(data, length), i, i, chunk_length) == 0 )
-        FORCE( b_cstring_memcmp(cstr, b_cstring_make_buf(data + i, length - i), i, 0, chunk_length) == 0 )
-    }
-}
-
-static void print_indent (int indent)
-{
-    for (int i = 0; i < indent; i++) {
-        printf("  ");
-    }
-}
-
-static void print_value (NCDValRef val, unsigned int indent)
-{
-    switch (NCDVal_Type(val)) {
-        case NCDVAL_STRING: {
-            NCDValNullTermString nts;
-            FORCE( NCDVal_StringNullTerminate(val, &nts) )
-            
-            print_indent(indent);
-            printf("string(%zu) %s\n", NCDVal_StringLength(val), nts.data);
-            
-            NCDValNullTermString_Free(&nts);
-        } break;
-        
-        case NCDVAL_LIST: {
-            size_t count = NCDVal_ListCount(val);
-            
-            print_indent(indent);
-            printf("list(%zu)\n", NCDVal_ListCount(val));
-            
-            for (size_t i = 0; i < count; i++) {
-                NCDValRef elem_val = NCDVal_ListGet(val, i);
-                print_value(elem_val, indent + 1);
-            }
-        } break;
-        
-        case NCDVAL_MAP: {
-            print_indent(indent);
-            printf("map(%zu)\n", NCDVal_MapCount(val));
-            
-            for (NCDValMapElem e = NCDVal_MapOrderedFirst(val); !NCDVal_MapElemInvalid(e); e = NCDVal_MapOrderedNext(val, e)) {
-                NCDValRef ekey = NCDVal_MapElemKey(val, e);
-                NCDValRef eval = NCDVal_MapElemVal(val, e);
-                
-                print_indent(indent + 1);
-                printf("key=\n");
-                print_value(ekey, indent + 2);
-                
-                print_indent(indent + 1);
-                printf("val=\n");
-                print_value(eval, indent + 2);
-            }
-        } break;
-    }
-}
-
-int main ()
-{
-    int res;
-    
-    BLog_InitStdout();
-    
-    NCDStringIndex string_index;
-    FORCE( NCDStringIndex_Init(&string_index) )
-    
-    // Some basic usage of values.
-    
-    NCDValMem mem;
-    NCDValMem_Init(&mem);
-    
-    NCDValRef s1 = NCDVal_NewString(&mem, "Hello World");
-    test_string(s1, "Hello World", 11);
-    ASSERT( NCDVal_IsString(s1) )
-    ASSERT( !NCDVal_IsIdString(s1) )
-    ASSERT( NCDVal_Type(s1) == NCDVAL_STRING )
-    
-    NCDValRef s2 = NCDVal_NewString(&mem, "This is reeeeeeeeeeeeeallllllllyyyyy fun!");
-    FORCE( !NCDVal_IsInvalid(s2) )
-    
-    NCDValRef l1 = NCDVal_NewList(&mem, 10);
-    FORCE( !NCDVal_IsInvalid(l1) )
-    
-    FORCE( NCDVal_ListAppend(l1, s1) )
-    FORCE( NCDVal_ListAppend(l1, s2) )
-    
-    print_value(s1, 0);
-    print_value(s2, 0);
-    print_value(l1, 0);
-    
-    NCDValRef k1 = NCDVal_NewString(&mem, "K1");
-    FORCE( !NCDVal_IsInvalid(k1) )
-    NCDValRef v1 = NCDVal_NewString(&mem, "V1");
-    FORCE( !NCDVal_IsInvalid(v1) )
-    
-    NCDValRef k2 = NCDVal_NewString(&mem, "K2");
-    FORCE( !NCDVal_IsInvalid(k2) )
-    NCDValRef v2 = NCDVal_NewString(&mem, "V2");
-    FORCE( !NCDVal_IsInvalid(v2) )
-    
-    NCDValRef m1 = NCDVal_NewMap(&mem, 3);
-    FORCE( !NCDVal_IsInvalid(m1) )
-    
-    FORCE( NCDVal_MapInsert(m1, k1, v1, &res) && res )
-    FORCE( NCDVal_MapInsert(m1, k2, v2, &res) && res )
-    
-    ASSERT( NCDVal_MapGetValue(m1, "K1").idx == v1.idx )
-    ASSERT( NCDVal_MapGetValue(m1, "K2").idx == v2.idx )
-    ASSERT( NCDVal_IsInvalid(NCDVal_MapGetValue(m1, "K3")) )
-    
-    NCDValRef ids1 = NCDVal_NewIdString(&mem, NCD_STRING_ARG1, &string_index);
-    test_string(ids1, "_arg1", 5);
-    ASSERT( !memcmp(NCDVal_StringData(ids1), "_arg1", 5) )
-    ASSERT( NCDVal_StringLength(ids1) == 5 )
-    ASSERT( !NCDVal_StringHasNulls(ids1) )
-    ASSERT( NCDVal_StringEquals(ids1, "_arg1") )
-    ASSERT( NCDVal_Type(ids1) == NCDVAL_STRING )
-    ASSERT( NCDVal_IsIdString(ids1) )
-    
-    NCDValRef ids2 = NCDVal_NewIdString(&mem, NCD_STRING_ARG2, &string_index);
-    test_string(ids2, "_arg2", 5);
-    ASSERT( !memcmp(NCDVal_StringData(ids2), "_arg2", 5) )
-    ASSERT( NCDVal_StringLength(ids2) == 5 )
-    ASSERT( !NCDVal_StringHasNulls(ids2) )
-    ASSERT( NCDVal_StringEquals(ids2, "_arg2") )
-    ASSERT( NCDVal_Type(ids2) == NCDVAL_STRING )
-    ASSERT( NCDVal_IsIdString(ids2) )
-    
-    FORCE( NCDVal_MapInsert(m1, ids1, ids2, &res) && res )
-    
-    ASSERT( NCDVal_MapGetValue(m1, "_arg1").idx == ids2.idx )
-    
-    print_value(m1, 0);
-    
-    NCDValRef copy = NCDVal_NewCopy(&mem, m1);
-    FORCE( !NCDVal_IsInvalid(copy) )
-    ASSERT( NCDVal_Compare(copy, m1) == 0 )
-    
-    NCDValMem_Free(&mem);
-    
-    // Try to make copies of a string within the same memory object.
-    // This is an evil test because we cannot simply copy a string using e.g.
-    // NCDVal_NewStringBin() - it requires that the buffer passed
-    // be outside the memory object of the new string.
-    // We use NCDVal_NewCopy(), which takes care of this by creating
-    // an uninitialized string using NCDVal_NewStringUninitialized() and
-    // then copyng the data.
-    
-    NCDValMem_Init(&mem);
-    
-    NCDValRef s[100];
-    
-    s[0] = NCDVal_NewString(&mem, "Eeeeeeeeeeeevil.");
-    FORCE( !NCDVal_IsInvalid(s[0]) )
-    
-    for (int i = 1; i < 100; i++) {
-        s[i] = NCDVal_NewCopy(&mem, s[i - 1]);
-        FORCE( !NCDVal_IsInvalid(s[i]) )
-        ASSERT( NCDVal_StringEquals(s[i - 1], "Eeeeeeeeeeeevil.") )
-        ASSERT( NCDVal_StringEquals(s[i], "Eeeeeeeeeeeevil.") )
-    }
-    
-    for (int i = 0; i < 100; i++) {
-        ASSERT( NCDVal_StringEquals(s[i], "Eeeeeeeeeeeevil.") )
-    }
-    
-    NCDValMem_Free(&mem);
-    
-    NCDValMem_Init(&mem);
-    
-    NCDValRef cstr1 = build_composed_string(&mem, "Hello World", 11, 3);
-    test_string(cstr1, "Hello World", 11);
-    FORCE( NCDVal_IsComposedString(cstr1) )
-    FORCE( !NCDVal_IsContinuousString(cstr1) )
-    FORCE( NCDVal_StringEquals(cstr1, "Hello World") )
-    FORCE( !NCDVal_StringEquals(cstr1, "Hello World ") )
-    FORCE( !NCDVal_StringEquals(cstr1, "Hello WorlD") )
-    
-    NCDValRef cstr2 = build_composed_string(&mem, "GoodBye", 7, 1);
-    test_string(cstr2, "GoodBye", 7);
-    FORCE( NCDVal_IsComposedString(cstr2) )
-    FORCE( !NCDVal_IsContinuousString(cstr2) )
-    FORCE( NCDVal_StringEquals(cstr2, "GoodBye") )
-    FORCE( !NCDVal_StringEquals(cstr2, " GoodBye") )
-    FORCE( !NCDVal_StringEquals(cstr2, "goodBye") )
-    
-    NCDValRef cstr3 = build_composed_string(&mem, "Bad\x00String", 10, 4);
-    test_string(cstr3, "Bad\x00String", 10);
-    FORCE( NCDVal_IsComposedString(cstr3) )
-    FORCE( !NCDVal_IsContinuousString(cstr3) )
-    
-    FORCE( NCDVal_StringMemCmp(cstr1, cstr2, 1, 2, 3) < 0 )
-    FORCE( NCDVal_StringMemCmp(cstr1, cstr2, 7, 1, 4) > 0 )
-    
-    char buf[10];
-    NCDVal_StringCopyOut(cstr1, 1, 10, buf);
-    FORCE( !memcmp(buf, "ello World", 10) )
-    
-    NCDValRef clist1 = NCDVal_NewList(&mem, 3);
-    FORCE( !NCDVal_IsInvalid(clist1) )
-    FORCE( NCDVal_ListAppend(clist1, cstr1) )
-    FORCE( NCDVal_ListAppend(clist1, cstr2) )
-    FORCE( NCDVal_ListAppend(clist1, cstr3) )
-    FORCE( NCDVal_ListCount(clist1) == 3 )
-    
-    FORCE( NCDValMem_ConvertNonContinuousStrings(&mem, &clist1) )
-    FORCE( NCDVal_ListCount(clist1) == 3 )
-    
-    NCDValRef fixed_str1 = NCDVal_ListGet(clist1, 0);
-    NCDValRef fixed_str2 = NCDVal_ListGet(clist1, 1);
-    NCDValRef fixed_str3 = NCDVal_ListGet(clist1, 2);
-    
-    FORCE( NCDVal_IsContinuousString(fixed_str1) )
-    FORCE( NCDVal_IsContinuousString(fixed_str2) )
-    FORCE( NCDVal_IsContinuousString(fixed_str3) )
-    
-    test_string(fixed_str1, "Hello World", 11);
-    test_string(fixed_str2, "GoodBye", 7);
-    test_string(fixed_str3, "Bad\x00String", 10);
-    
-    NCDValMem_Free(&mem);
-    
-    NCDStringIndex_Free(&string_index);
-    
-    return 0;
-}
diff --git a/external/badvpn_dns/examples/ncdvalcons_test.c b/external/badvpn_dns/examples/ncdvalcons_test.c
deleted file mode 100644
index 7a876ed..0000000
--- a/external/badvpn_dns/examples/ncdvalcons_test.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * @file ncdvalcons_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-#include <stdio.h>
-
-#include <misc/debug.h>
-#include <ncd/NCDValCons.h>
-#include <ncd/NCDValGenerator.h>
-
-static NCDValMem mem;
-static NCDValCons cons;
-
-static NCDValConsVal make_string (const char *data)
-{
-    NCDValConsVal val;
-    int error;
-    int res = NCDValCons_NewString(&cons, (const uint8_t *)data, strlen(data), &val, &error);
-    ASSERT_FORCE(res)
-    return val;
-}
-
-static NCDValConsVal make_list (void)
-{
-    NCDValConsVal val;
-    NCDValCons_NewList(&cons, &val);
-    return val;
-}
-
-static NCDValConsVal make_map (void)
-{
-    NCDValConsVal val;
-    NCDValCons_NewMap(&cons, &val);
-    return val;
-}
-
-static NCDValConsVal list_prepend (NCDValConsVal list, NCDValConsVal elem)
-{
-    int error;
-    int res = NCDValCons_ListPrepend(&cons, &list, elem, &error);
-    ASSERT_FORCE(res)
-    return list;
-}
-
-static NCDValConsVal map_insert (NCDValConsVal map, NCDValConsVal key, NCDValConsVal value)
-{
-    int error;
-    int res = NCDValCons_MapInsert(&cons, &map, key, value, &error);
-    ASSERT_FORCE(res)
-    return map;
-}
-
-static NCDValRef complete (NCDValConsVal cval)
-{
-    int error;
-    NCDValRef val;
-    int res = NCDValCons_Complete(&cons, cval, &val, &error);
-    ASSERT_FORCE(res)
-    return val;
-}
-
-int main ()
-{
-    NCDValMem_Init(&mem);
-    
-    int res = NCDValCons_Init(&cons, &mem);
-    ASSERT_FORCE(res)
-    
-    NCDValRef val1 = complete(list_prepend(list_prepend(list_prepend(make_list(), make_string("hello")), make_string("world")), make_list()));
-    char *str1 = NCDValGenerator_Generate(val1);
-    ASSERT_FORCE(str1)
-    ASSERT_FORCE(!strcmp(str1, "{{}, \"world\", \"hello\"}"))
-    free(str1);
-    
-    NCDValRef val2 = complete(map_insert(map_insert(map_insert(make_map(), make_list(), make_list()), make_string("A"), make_list()), make_string("B"), make_list()));
-    char *str2 = NCDValGenerator_Generate(val2);
-    ASSERT_FORCE(str2)
-    printf("%s\n", str2);
-    ASSERT_FORCE(!strcmp(str2, "[\"A\":{}, \"B\":{}, {}:{}]"))
-    free(str2);
-    
-    NCDValCons_Free(&cons);
-    NCDValMem_Free(&mem);
-    return 0;
-}
diff --git a/external/badvpn_dns/examples/parse_number_test.c b/external/badvpn_dns/examples/parse_number_test.c
deleted file mode 100644
index d393c3f..0000000
--- a/external/badvpn_dns/examples/parse_number_test.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * @file parse_number_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <inttypes.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <time.h>
-
-#include <misc/parse_number.h>
-#include <misc/debug.h>
-
-static void test_random (int num_digits, int digit_modulo)
-{
-    ASSERT(num_digits > 0);
-    ASSERT(digit_modulo > 0);
-    
-    uint8_t digits[40];
-    
-    for (int i = 0; i < num_digits; i++) {
-        digits[i] = '0' + (rand() % digit_modulo);
-    }
-    digits[num_digits] = '\0';
-    
-    char *endptr;
-    uintmax_t std_num = strtoumax((const char *)digits, &endptr, 10);
-    int std_res = !*endptr && !(std_num == UINTMAX_MAX && errno == ERANGE);
-    
-    uintmax_t num = 0;
-    int res = parse_unsigned_integer_bin((const char *)digits, num_digits, &num);
-    
-    if (res != std_res) {
-        printf("fail1 %s\n", (const char *)digits);
-        ASSERT_FORCE(0);
-    }
-    
-    if (res && num != std_num) {
-        printf("fail2 %s\n", (const char *)digits);
-        ASSERT_FORCE(0);
-    }
-    
-    if (res) {
-        uint8_t *nozero_digits = digits;
-        while (*nozero_digits == '0' && nozero_digits != &digits[num_digits - 1]) {
-            nozero_digits++;
-        }
-        
-        char buf[40];
-        int size = compute_decimal_repr_size(num);
-        generate_decimal_repr(num, buf, size);
-        buf[size] = '\0';
-        ASSERT_FORCE(!strcmp(buf, (const char *)nozero_digits));
-    }
-}
-
-static void test_value (uintmax_t x)
-{
-    char str[40];
-    sprintf(str, "%" PRIuMAX, x);
-    uintmax_t y;
-    int res = parse_unsigned_integer_bin(str, strlen(str), &y);
-    ASSERT_FORCE(res);
-    ASSERT_FORCE(y == x);
-    
-    char str2[40];
-    int size = compute_decimal_repr_size(x);
-    generate_decimal_repr(x, str2, size);
-    str2[size] = '\0';
-    
-    ASSERT_FORCE(!strcmp(str2, str));
-}
-
-static void test_value_range (uintmax_t start, uintmax_t count)
-{
-    uintmax_t i = start;
-    do {
-        test_value(i);
-        i++;
-    } while (i != start + count);
-}
-
-int main ()
-{
-    srand(time(NULL));
-    
-    for (int num_digits = 1; num_digits <= 22; num_digits++) {
-        for (int i = 0; i < 1000000; i++) {
-            test_random(num_digits, 10);
-        }
-        for (int i = 0; i < 1000000; i++) {
-            test_random(num_digits, 11);
-        }
-    }
-    
-    test_value_range(UINTMAX_C(0), 5000000);
-    test_value_range(UINTMAX_C(100000000), 5000000);
-    test_value_range(UINTMAX_C(258239003), 5000000);
-    test_value_range(UINTMAX_C(8241096180752634), 5000000);
-    test_value_range(UINTMAX_C(9127982390882308083), 5000000);
-    test_value_range(UINTMAX_C(18446744073700000000), 20000000);
-    
-    return 0;
-}
diff --git a/external/badvpn_dns/examples/predicate_test.c b/external/badvpn_dns/examples/predicate_test.c
deleted file mode 100644
index 324a960..0000000
--- a/external/badvpn_dns/examples/predicate_test.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/**
- * @file predicate_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <predicate/BPredicate.h>
-#include <base/BLog.h>
-
-static int func_hello (void *user, void **args)
-{
-    return 1;
-}
-
-static int func_neg (void *user, void **args)
-{
-    int arg = *((int *)args[0]);
-    
-    return !arg;
-}
-
-static int func_conj (void *user, void **args)
-{
-    int arg1 = *((int *)args[0]);
-    int arg2 = *((int *)args[1]);
-    
-    return (arg1 && arg2);
-}
-
-static int func_strcmp (void *user, void **args)
-{
-    char *arg1 = (char *)args[0];
-    char *arg2 = (char *)args[1];
-    
-    return (!strcmp(arg1, arg2));
-}
-
-static int func_error (void *user, void **args)
-{
-    return -1;
-}
-
-int main (int argc, char **argv)
-{
-    if (argc != 2) {
-        fprintf(stderr, "Usage: %s <predicate>\n", argv[0]);
-        return 1;
-    }
-    
-    // init logger
-    BLog_InitStdout();
-    
-    // init predicate
-    BPredicate pr;
-    if (!BPredicate_Init(&pr, argv[1])) {
-        fprintf(stderr, "BPredicate_Init failed\n");
-        return 1;
-    }
-    
-    // init functions
-    BPredicateFunction f_hello;
-    BPredicateFunction_Init(&f_hello, &pr, "hello", NULL, 0, func_hello, NULL);
-    int arr1[] = {PREDICATE_TYPE_BOOL};
-    BPredicateFunction f_neg;
-    BPredicateFunction_Init(&f_neg, &pr, "neg", arr1, 1, func_neg, NULL);
-    int arr2[] = {PREDICATE_TYPE_BOOL, PREDICATE_TYPE_BOOL};
-    BPredicateFunction f_conj;
-    BPredicateFunction_Init(&f_conj, &pr, "conj", arr2, 2, func_conj, NULL);
-    int arr3[] = {PREDICATE_TYPE_STRING, PREDICATE_TYPE_STRING};
-    BPredicateFunction f_strcmp;
-    BPredicateFunction_Init(&f_strcmp, &pr, "strcmp", arr3, 2, func_strcmp, NULL);
-    BPredicateFunction f_error;
-    BPredicateFunction_Init(&f_error, &pr, "error", NULL, 0, func_error, NULL);
-    
-    // evaluate
-    int result = BPredicate_Eval(&pr);
-    printf("%d\n", result);
-    
-    // free functions
-    BPredicateFunction_Free(&f_hello);
-    BPredicateFunction_Free(&f_neg);
-    BPredicateFunction_Free(&f_conj);
-    BPredicateFunction_Free(&f_strcmp);
-    BPredicateFunction_Free(&f_error);
-    
-    // free predicate
-    BPredicate_Free(&pr);
-    
-    return 0;
-}
diff --git a/external/badvpn_dns/examples/savl_test.c b/external/badvpn_dns/examples/savl_test.c
deleted file mode 100644
index 18cf191..0000000
--- a/external/badvpn_dns/examples/savl_test.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/**
- * @file savl_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-#include <limits.h>
-
-#include <misc/debug.h>
-#include <misc/balloc.h>
-#include <misc/compare.h>
-#include <structure/SAvl.h>
-#include <security/BRandom.h>
-
-struct mynode;
-
-#include "savl_test_tree.h"
-#include <structure/SAvl_decl.h>
-
-struct mynode {
-    int used;
-    int num;
-    MyTreeNode tree_node;
-};
-
-#include "savl_test_tree.h"
-#include <structure/SAvl_impl.h>
-
-static void verify (MyTree *tree)
-{
-    printf("Verifying...\n");
-    MyTree_Verify(tree, 0);
-}
-
-int main (int argc, char **argv)
-{
-    int num_nodes;
-    int num_random_delete;
-    
-    if (argc != 3 || (num_nodes = atoi(argv[1])) <= 0 || (num_random_delete = atoi(argv[2])) < 0) {
-        fprintf(stderr, "Usage: %s <num> <numrandomdelete>\n", (argc > 0 ? argv[0] : NULL));
-        return 1;
-    }
-    
-    struct mynode *nodes = (struct mynode *)BAllocArray(num_nodes, sizeof(*nodes));
-    ASSERT_FORCE(nodes)
-    
-    int *values_ins = (int *)BAllocArray(num_nodes, sizeof(int));
-    ASSERT_FORCE(values_ins)
-    
-    int *values = (int *)BAllocArray(num_random_delete, sizeof(int));
-    ASSERT_FORCE(values)
-    
-    MyTree tree;
-    MyTree_Init(&tree);
-    verify(&tree);
-    
-    printf("Inserting random values...\n");
-    int inserted = 0;
-    BRandom_randomize((uint8_t *)values_ins, num_nodes * sizeof(int));
-    for (int i = 0; i < num_nodes; i++) {
-        nodes[i].num = values_ins[i];
-        if (MyTree_Insert(&tree, 0, &nodes[i], NULL)) {
-            nodes[i].used = 1;
-            inserted++;
-        } else {
-            nodes[i].used = 0;
-            printf("Insert collision!\n");
-        }
-    }
-    printf("Inserted %d entries\n", inserted);
-    ASSERT_FORCE(MyTree_Count(&tree, 0) == inserted)
-    verify(&tree);
-    
-    printf("Removing random entries...\n");
-    int removed1 = 0;
-    BRandom_randomize((uint8_t *)values, num_random_delete * sizeof(int));
-    for (int i = 0; i < num_random_delete; i++) {
-        int index = (((unsigned int *)values)[i] % num_nodes);
-        struct mynode *node = nodes + index;
-        if (node->used) {
-            MyTree_Remove(&tree, 0, node);
-            node->used = 0;
-            removed1++;
-        }
-    }
-    printf("Removed %d entries\n", removed1);
-    ASSERT_FORCE(MyTree_Count(&tree, 0) == inserted - removed1)
-    verify(&tree);
-    
-    printf("Removing remaining...\n");
-    int removed2 = 0;
-    while (!MyTree_IsEmpty(&tree)) {
-        struct mynode *node = MyTree_GetFirst(&tree, 0);
-        ASSERT_FORCE(node->used)
-        MyTree_Remove(&tree, 0, node);
-        node->used = 0;
-        removed2++;
-    }
-    printf("Removed %d entries\n", removed2);
-    ASSERT_FORCE(MyTree_IsEmpty(&tree))
-    ASSERT_FORCE(removed1 + removed2 == inserted)
-    ASSERT_FORCE(MyTree_Count(&tree, 0) == 0)
-    verify(&tree);
-    
-    BFree(nodes);
-    BFree(values_ins);
-    BFree(values);
-    
-    return 0;
-}
diff --git a/external/badvpn_dns/examples/savl_test_tree.h b/external/badvpn_dns/examples/savl_test_tree.h
deleted file mode 100644
index 41964e9..0000000
--- a/external/badvpn_dns/examples/savl_test_tree.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#define SAVL_PARAM_NAME MyTree
-#define SAVL_PARAM_FEATURE_COUNTS 1
-#define SAVL_PARAM_FEATURE_NOKEYS 1
-#define SAVL_PARAM_TYPE_ENTRY struct mynode
-#define SAVL_PARAM_TYPE_ARG int
-#define SAVL_PARAM_TYPE_COUNT int
-#define SAVL_PARAM_VALUE_COUNT_MAX INT_MAX
-#define SAVL_PARAM_FUN_COMPARE_ENTRIES(arg, entry1, entry2) B_COMPARE((entry1)->num, (entry2)->num)
-#define SAVL_PARAM_MEMBER_NODE tree_node
diff --git a/external/badvpn_dns/examples/stdin_input.c b/external/badvpn_dns/examples/stdin_input.c
deleted file mode 100644
index 8ff752c..0000000
--- a/external/badvpn_dns/examples/stdin_input.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/**
- * @file stdin_input.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Example program which reads stdin and waits for SIGINT and SIGTERM.
- */
-
-#include <stdio.h>
-#include <stddef.h>
-
-#include <base/DebugObject.h>
-#include <system/BReactor.h>
-#include <system/BNetwork.h>
-#include <system/BConnection.h>
-#include <system/BUnixSignal.h>
-
-#define BUF_SIZE 64
-
-BReactor reactor;
-BConnection pipe_con;
-BUnixSignal usignal;
-StreamRecvInterface *source_if;
-uint8_t buf[BUF_SIZE + 1];
-
-static void signal_handler (void *user, int signo)
-{
-    fprintf(stderr, "received %s, exiting\n", (signo == SIGINT ? "SIGINT" : "SIGTERM"));
-    
-    // exit event loop
-    BReactor_Quit(&reactor, 1);
-}
-
-static void connection_handler (void *user, int event)
-{
-    if (event == BCONNECTION_EVENT_RECVCLOSED) {
-        fprintf(stderr, "pipe closed\n");
-    } else {
-        fprintf(stderr, "pipe error\n");
-    }
-    
-    // exit event loop
-    BReactor_Quit(&reactor, (event == BCONNECTION_EVENT_RECVCLOSED ? 0 : 1));
-}
-
-static void input_handler_done (void *user, int data_len)
-{
-    // receive next chunk
-    StreamRecvInterface_Receiver_Recv(source_if, buf, BUF_SIZE);
-    
-    // print this chunk
-    buf[data_len] = '\0';
-    printf("Received: '%s'\n", buf);
-}
-
-int main ()
-{
-    int ret = 1;
-    
-    BLog_InitStdout();
-    
-    // init network
-    if (!BNetwork_GlobalInit()) {
-        fprintf(stderr, "BNetwork_GlobalInit failed\n");
-        goto fail1;
-    }
-    
-    // init reactor (event loop)
-    if (!BReactor_Init(&reactor)) {
-        fprintf(stderr, "BReactor_Init failed\n");
-        goto fail1;
-    }
-    
-    // init signal handling
-    sigset_t set;
-    sigemptyset(&set);
-    sigaddset(&set, SIGINT);
-    sigaddset(&set, SIGTERM);
-    if (!BUnixSignal_Init(&usignal, &reactor, set, signal_handler, NULL)) {
-        fprintf(stderr, "BUnixSignal_Init failed\n");
-        goto fail2;
-    }
-    
-    // init BConnection object backed by the stdin fd
-    if (!BConnection_Init(&pipe_con, BConnection_source_pipe(0), &reactor, NULL, connection_handler)) {
-        fprintf(stderr, "BConnection_Init failed\n");
-        goto fail3;
-    }
-    
-    // init connection receive interface
-    BConnection_RecvAsync_Init(&pipe_con);
-    source_if = BConnection_RecvAsync_GetIf(&pipe_con);
-    
-    // init receive done callback
-    StreamRecvInterface_Receiver_Init(source_if, input_handler_done, NULL);
-    
-    // receive first chunk
-    StreamRecvInterface_Receiver_Recv(source_if, buf, BUF_SIZE);
-    
-    // run event loop
-    ret = BReactor_Exec(&reactor);
-    
-    BConnection_RecvAsync_Free(&pipe_con);
-    BConnection_Free(&pipe_con);
-fail3:
-    BUnixSignal_Free(&usignal, 0);
-fail2:
-    BReactor_Free(&reactor);
-fail1:
-    BLog_Free();
-    DebugObjectGlobal_Finish();
-    return ret;
-}
diff --git a/external/badvpn_dns/examples/substring_test.c b/external/badvpn_dns/examples/substring_test.c
deleted file mode 100644
index 4a4b6c8..0000000
--- a/external/badvpn_dns/examples/substring_test.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/**
- * @file substring_test.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <time.h>
-
-#include <misc/substring.h>
-#include <misc/debug.h>
-#include <misc/balloc.h>
-#include <misc/print_macros.h>
-
-static int find_substring_slow (const char *str, size_t str_len, const char *sub, size_t sub_len, size_t *out_pos)
-{
-    ASSERT(sub_len > 0)
-    
-    if (str_len < sub_len) {
-        return 0;
-    }
-    
-    for (size_t i = 0; i <= str_len - sub_len; i++) {
-        if (!memcmp(str + i, sub, sub_len)) {
-            *out_pos = i;
-            return 1;
-        }
-    }
-    
-    return 0;
-}
-
-static void print_data (const char *str, size_t str_len)
-{
-    while (str_len > 0) {
-        printf("%02"PRIx8" ", (uint8_t)(*str));
-        str++;
-        str_len--;
-    }
-    printf("\n");
-}
-
-static void print_table (const size_t *table, size_t len)
-{
-    for (size_t i = 1; i < len; i++) {
-        printf("%zu ", table[i]);
-    }
-    printf("\n");
-}
-
-static void test_tables (int len, int count)
-{
-    ASSERT(len > 0)
-    ASSERT(count >= 0)
-    
-    char *word = (char *)BAllocSize(bsize_fromint(len));
-    ASSERT_FORCE(word)
-    
-    size_t *table = (size_t *)BAllocSize(bsize_mul(bsize_fromint(len), bsize_fromsize(sizeof(table[0]))));
-    ASSERT_FORCE(table)
-    
-    for (int i = 0; i < count; i++) {
-        for (int j = 0; j < len; j++) {
-            word[j] = rand() % 2;
-        }
-        
-        build_substring_backtrack_table(word, len, table);
-        
-        for (int j = 1; j < len; j++) {
-            for (int k = j - 1; k >= 0; k--) {
-                if (!memcmp(word + j - k, word, k)) {
-                    ASSERT_FORCE(table[j] == k)
-                    break;
-                }
-            }
-        }
-    }
-    
-    BFree(table);
-    BFree(word);
-}
-
-static void test_substring (int word_len, int text_len, int word_count, int text_count)
-{
-    assert(word_len > 0);
-    assert(text_len >= 0);
-    assert(word_count >= 0);
-    assert(text_count >= 0);
-    
-    char *word = (char *)BAllocSize(bsize_fromint(word_len));
-    ASSERT_FORCE(word)
-    
-    size_t *table = (size_t *)BAllocSize(bsize_mul(bsize_fromint(word_len), bsize_fromsize(sizeof(table[0]))));
-    ASSERT_FORCE(table)
-    
-    char *text = (char *)BAllocSize(bsize_fromint(text_len));
-    ASSERT_FORCE(text)
-    
-    for (int i = 0; i < word_count; i++) {
-        for (int j = 0; j < word_len; j++) {
-            word[j] = rand() % 2;
-        }
-        
-        build_substring_backtrack_table(word, word_len, table);
-        
-        for (int j = 0; j < text_count; j++) {
-            for (int k = 0; k < text_len; k++) {
-                text[k] = rand() % 2;
-            }
-            
-            size_t pos = 36; // to remove warning
-            int res = find_substring(text, text_len, word, word_len, table, &pos);
-            
-            size_t spos = 59; // to remove warning
-            int sres = find_substring_slow(text, text_len, word, word_len, &spos);
-            
-            ASSERT_FORCE(res == sres)
-            if (res) {
-                ASSERT_FORCE(pos == spos)
-            }
-        }
-    }
-    
-    BFree(text);
-    BFree(table);
-    BFree(word);
-}
-
-int main (int argc, char *argv[])
-{
-    if (argc != 7) {
-        printf("Usage: %s <tables length> <tables count> <word len> <text len> <word count> <text count>\n", (argc == 0 ? "" : argv[0]));
-        return 1;
-    }
-    
-    int tables_len = atoi(argv[1]);
-    int tables_count = atoi(argv[2]);
-    int word_len = atoi(argv[3]);
-    int text_len = atoi(argv[4]);
-    int word_count = atoi(argv[5]);
-    int text_count = atoi(argv[6]);
-    
-    if (tables_len <= 0 || tables_count < 0 || word_len <= 0 || text_len < 0 || word_count < 0 || text_count < 0) {
-        printf("Bad arguments.\n");
-        return 1;
-    }
-    
-    srand(time(NULL));
-    
-    test_tables(tables_len, tables_count);
-    
-    test_substring(word_len, text_len, word_count, text_count);
-    
-    {
-        char text[] = "aggagaa";
-        char word[] = "aga";
-        size_t table[sizeof(word) - 1];
-        build_substring_backtrack_table(word, strlen(word), table);
-        
-        size_t pos;
-        int res = find_substring(text, strlen(text), word, strlen(word), table, &pos);
-        ASSERT_FORCE(res)
-        ASSERT_FORCE(pos == 3)
-    }
-    
-    {
-        char text[] = "aagagga";
-        char word[] = "aga";
-        size_t table[sizeof(word) - 1];
-        build_substring_backtrack_table_reverse(word, strlen(word), table);
-        
-        size_t pos;
-        int res = find_substring_reverse(text, strlen(text), word, strlen(word), table, &pos);
-        ASSERT_FORCE(res)
-        ASSERT_FORCE(pos == 1)
-    }
-    
-    return 0;
-}
diff --git a/external/badvpn_dns/fix_flex.php b/external/badvpn_dns/fix_flex.php
deleted file mode 100644
index bd026d0..0000000
--- a/external/badvpn_dns/fix_flex.php
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-
-$filename = $argv[1];
-$contents = file_get_contents($filename);
-if ($contents === FALSE) exit(1);
-$search = array("<inttypes.h>", "#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L");
-$replace = array("<stdint.h>", "#if 1");
-$contents = str_replace($search, $replace, $contents);
-$res = file_put_contents($filename, $contents);
-if ($res === FALSE) exit(1);
diff --git a/external/badvpn_dns/flooder/CMakeLists.txt b/external/badvpn_dns/flooder/CMakeLists.txt
deleted file mode 100644
index 36253ab..0000000
--- a/external/badvpn_dns/flooder/CMakeLists.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-add_executable(badvpn-flooder flooder.c)
-target_link_libraries(badvpn-flooder system flow server_conection ${NSPR_LIBRARIES} ${NSS_LIBRARIES})
-
-install(
-    TARGETS badvpn-flooder
-    RUNTIME DESTINATION bin
-)
diff --git a/external/badvpn_dns/flooder/flooder.c b/external/badvpn_dns/flooder/flooder.c
deleted file mode 100644
index 1f3f05c..0000000
--- a/external/badvpn_dns/flooder/flooder.c
+++ /dev/null
@@ -1,671 +0,0 @@
-/**
- * @file flooder.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <protocol/addr.h>
-#include <protocol/scproto.h>
-#include <misc/loglevel.h>
-#include <misc/version.h>
-#include <misc/nsskey.h>
-#include <misc/byteorder.h>
-#include <misc/loggers_string.h>
-#include <misc/open_standard_streams.h>
-#include <base/BLog.h>
-#include <system/BReactor.h>
-#include <system/BSignal.h>
-#include <system/BNetwork.h>
-#include <flow/SinglePacketBuffer.h>
-#include <flow/PacketProtoEncoder.h>
-#include <nspr_support/BSSLConnection.h>
-#include <server_connection/ServerConnection.h>
-
-#ifndef BADVPN_USE_WINAPI
-#include <base/BLog_syslog.h>
-#endif
-
-#include <flooder/flooder.h>
-
-#include <generated/blog_channel_flooder.h>
-
-#define LOGGER_STDOUT 1
-#define LOGGER_SYSLOG 2
-
-// command-line options
-struct {
-    int help;
-    int version;
-    int logger;
-    #ifndef BADVPN_USE_WINAPI
-    char *logger_syslog_facility;
-    char *logger_syslog_ident;
-    #endif
-    int loglevel;
-    int loglevels[BLOG_NUM_CHANNELS];
-    int ssl;
-    char *nssdb;
-    char *client_cert_name;
-    char *server_name;
-    char *server_addr;
-    peerid_t floods[MAX_FLOODS];
-    int num_floods;
-} options;
-
-// server address we connect to
-BAddr server_addr;
-
-// server name to use for SSL
-char server_name[256];
-
-// reactor
-BReactor ss;
-
-// client certificate if using SSL
-CERTCertificate *client_cert;
-
-// client private key if using SSL
-SECKEYPrivateKey *client_key;
-
-// server connection
-ServerConnection server;
-
-// whether server is ready
-int server_ready;
-
-// my ID, defined only after server_ready
-peerid_t my_id;
-
-// flooding output
-PacketRecvInterface flood_source;
-PacketProtoEncoder flood_encoder;
-SinglePacketBuffer flood_buffer;
-
-// whether we were asked for a packet and blocked
-int flood_blocking;
-
-// index of next peer to send packet too
-int flood_next;
-
-/**
- * Cleans up everything that can be cleaned up from inside the event loop.
- */
-static void terminate (void);
-
-/**
- * Prints command line help.
- */
-static void print_help (const char *name);
-
-/**
- * Prints program name, version and copyright notice.
- */
-static void print_version (void);
-
-/**
- * Parses command line options into the options strucute.
- *
- * @return 1 on success, 0 on failure
- */
-static int parse_arguments (int argc, char *argv[]);
-
-/**
- * Processes command line options.
- *
- * @return 1 on success, 0 on failure
- */
-static int resolve_arguments (void);
-
-/**
- * Handler invoked when program termination is requested.
- */
-static void signal_handler (void *unused);
-
-static void server_handler_error (void *user);
-static void server_handler_ready (void *user, peerid_t param_my_id, uint32_t ext_ip);
-static void server_handler_newclient (void *user, peerid_t peer_id, int flags, const uint8_t *cert, int cert_len);
-static void server_handler_endclient (void *user, peerid_t peer_id);
-static void server_handler_message (void *user, peerid_t peer_id, uint8_t *data, int data_len);
-
-static void flood_source_handler_recv (void *user, uint8_t *data);
-
-int main (int argc, char *argv[])
-{
-    if (argc <= 0) {
-        return 1;
-    }
-    
-    // open standard streams
-    open_standard_streams();
-    
-    // parse command-line arguments
-    if (!parse_arguments(argc, argv)) {
-        fprintf(stderr, "Failed to parse arguments\n");
-        print_help(argv[0]);
-        goto fail0;
-    }
-    
-    // handle --help and --version
-    if (options.help) {
-        print_version();
-        print_help(argv[0]);
-        return 0;
-    }
-    if (options.version) {
-        print_version();
-        return 0;
-    }
-    
-    // initialize logger
-    switch (options.logger) {
-        case LOGGER_STDOUT:
-            BLog_InitStdout();
-            break;
-        #ifndef BADVPN_USE_WINAPI
-        case LOGGER_SYSLOG:
-            if (!BLog_InitSyslog(options.logger_syslog_ident, options.logger_syslog_facility)) {
-                fprintf(stderr, "Failed to initialize syslog logger\n");
-                goto fail0;
-            }
-            break;
-        #endif
-        default:
-            ASSERT(0);
-    }
-    
-    // configure logger channels
-    for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
-        if (options.loglevels[i] >= 0) {
-            BLog_SetChannelLoglevel(i, options.loglevels[i]);
-        }
-        else if (options.loglevel >= 0) {
-            BLog_SetChannelLoglevel(i, options.loglevel);
-        }
-    }
-    
-    BLog(BLOG_NOTICE, "initializing "GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION);
-    
-    // initialize network
-    if (!BNetwork_GlobalInit()) {
-        BLog(BLOG_ERROR, "BNetwork_GlobalInit failed");
-        goto fail1;
-    }
-    
-    // init time
-    BTime_Init();
-    
-    // resolve addresses
-    if (!resolve_arguments()) {
-        BLog(BLOG_ERROR, "Failed to resolve arguments");
-        goto fail1;
-    }
-    
-    // init reactor
-    if (!BReactor_Init(&ss)) {
-        BLog(BLOG_ERROR, "BReactor_Init failed");
-        goto fail1;
-    }
-    
-    // setup signal handler
-    if (!BSignal_Init(&ss, signal_handler, NULL)) {
-        BLog(BLOG_ERROR, "BSignal_Init failed");
-        goto fail1a;
-    }
-    
-    if (options.ssl) {
-        // init NSPR
-        PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
-        
-        // register local NSPR file types
-        if (!BSSLConnection_GlobalInit()) {
-            BLog(BLOG_ERROR, "BSSLConnection_GlobalInit failed");
-            goto fail3;
-        }
-        
-        // init NSS
-        if (NSS_Init(options.nssdb) != SECSuccess) {
-            BLog(BLOG_ERROR, "NSS_Init failed (%d)", (int)PR_GetError());
-            goto fail2;
-        }
-        
-        // set cipher policy
-        if (NSS_SetDomesticPolicy() != SECSuccess) {
-            BLog(BLOG_ERROR, "NSS_SetDomesticPolicy failed (%d)", (int)PR_GetError());
-            goto fail3;
-        }
-        
-        // init server cache
-        if (SSL_ConfigServerSessionIDCache(0, 0, 0, NULL) != SECSuccess) {
-            BLog(BLOG_ERROR, "SSL_ConfigServerSessionIDCache failed (%d)", (int)PR_GetError());
-            goto fail3;
-        }
-        
-        // open server certificate and private key
-        if (!open_nss_cert_and_key(options.client_cert_name, &client_cert, &client_key)) {
-            BLog(BLOG_ERROR, "Cannot open certificate and key");
-            goto fail4;
-        }
-    }
-    
-    // start connecting to server
-    if (!ServerConnection_Init(
-        &server, &ss, NULL, server_addr, SC_KEEPALIVE_INTERVAL, SERVER_BUFFER_MIN_PACKETS, options.ssl, 0, client_cert, client_key, server_name, NULL,
-        server_handler_error, server_handler_ready, server_handler_newclient, server_handler_endclient, server_handler_message
-    )) {
-        BLog(BLOG_ERROR, "ServerConnection_Init failed");
-        goto fail5;
-    }
-    
-    // set server not ready
-    server_ready = 0;
-    
-    // enter event loop
-    BLog(BLOG_NOTICE, "entering event loop");
-    BReactor_Exec(&ss);
-    
-    if (server_ready) {
-        ServerConnection_ReleaseBuffers(&server);
-        SinglePacketBuffer_Free(&flood_buffer);
-        PacketProtoEncoder_Free(&flood_encoder);
-        PacketRecvInterface_Free(&flood_source);
-    }
-    
-    ServerConnection_Free(&server);
-fail5:
-    if (options.ssl) {
-        CERT_DestroyCertificate(client_cert);
-        SECKEY_DestroyPrivateKey(client_key);
-fail4:
-        ASSERT_FORCE(SSL_ShutdownServerSessionIDCache() == SECSuccess)
-fail3:
-        SSL_ClearSessionCache();
-        ASSERT_FORCE(NSS_Shutdown() == SECSuccess)
-fail2:
-        ASSERT_FORCE(PR_Cleanup() == PR_SUCCESS)
-        PL_ArenaFinish();
-    }
-    
-    BSignal_Finish();
-fail1a:
-    BReactor_Free(&ss);
-fail1:
-    BLog(BLOG_NOTICE, "exiting");
-    BLog_Free();
-fail0:
-    DebugObjectGlobal_Finish();
-    
-    return 1;
-}
-
-void terminate (void)
-{
-    BLog(BLOG_NOTICE, "tearing down");
-    
-    // exit event loop
-    BReactor_Quit(&ss, 0);
-}
-
-void print_help (const char *name)
-{
-    printf(
-        "Usage:\n"
-        "    %s\n"
-        "        [--help]\n"
-        "        [--version]\n"
-        "        [--logger <"LOGGERS_STRING">]\n"
-        #ifndef BADVPN_USE_WINAPI
-        "        (logger=syslog?\n"
-        "            [--syslog-facility <string>]\n"
-        "            [--syslog-ident <string>]\n"
-        "        )\n"
-        #endif
-        "        [--loglevel <0-5/none/error/warning/notice/info/debug>]\n"
-        "        [--channel-loglevel <channel-name> <0-5/none/error/warning/notice/info/debug>] ...\n"
-        "        [--ssl --nssdb <string> --client-cert-name <string>]\n"
-        "        [--server-name <string>]\n"
-        "        --server-addr <addr>\n"
-        "        [--flood-id <id>] ...\n"
-        "Address format is a.b.c.d:port (IPv4) or [addr]:port (IPv6).\n",
-        name
-    );
-}
-
-void print_version (void)
-{
-    printf(GLOBAL_PRODUCT_NAME" "PROGRAM_NAME" "GLOBAL_VERSION"\n"GLOBAL_COPYRIGHT_NOTICE"\n");
-}
-
-int parse_arguments (int argc, char *argv[])
-{
-    if (argc <= 0) {
-        return 0;
-    }
-    
-    options.help = 0;
-    options.version = 0;
-    options.logger = LOGGER_STDOUT;
-    #ifndef BADVPN_USE_WINAPI
-    options.logger_syslog_facility = "daemon";
-    options.logger_syslog_ident = argv[0];
-    #endif
-    options.loglevel = -1;
-    for (int i = 0; i < BLOG_NUM_CHANNELS; i++) {
-        options.loglevels[i] = -1;
-    }
-    options.ssl = 0;
-    options.nssdb = NULL;
-    options.client_cert_name = NULL;
-    options.server_name = NULL;
-    options.server_addr = NULL;
-    options.num_floods = 0;
-    
-    int i;
-    for (i = 1; i < argc; i++) {
-        char *arg = argv[i];
-        if (!strcmp(arg, "--help")) {
-            options.help = 1;
-        }
-        else if (!strcmp(arg, "--version")) {
-            options.version = 1;
-        }
-        else if (!strcmp(arg, "--logger")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            char *arg2 = argv[i + 1];
-            if (!strcmp(arg2, "stdout")) {
-                options.logger = LOGGER_STDOUT;
-            }
-            #ifndef BADVPN_USE_WINAPI
-            else if (!strcmp(arg2, "syslog")) {
-                options.logger = LOGGER_SYSLOG;
-            }
-            #endif
-            else {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        #ifndef BADVPN_USE_WINAPI
-        else if (!strcmp(arg, "--syslog-facility")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.logger_syslog_facility = argv[i + 1];
-            i++;
-        }
-        else if (!strcmp(arg, "--syslog-ident")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.logger_syslog_ident = argv[i + 1];
-            i++;
-        }
-        #endif
-        else if (!strcmp(arg, "--loglevel")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if ((options.loglevel = parse_loglevel(argv[i + 1])) < 0) {
-                fprintf(stderr, "%s: wrong argument\n", arg);
-                return 0;
-            }
-            i++;
-        }
-        else if (!strcmp(arg, "--channel-loglevel")) {
-            if (2 >= argc - i) {
-                fprintf(stderr, "%s: requires two arguments\n", arg);
-                return 0;
-            }
-            int channel = BLogGlobal_GetChannelByName(argv[i + 1]);
-            if (channel < 0) {
-                fprintf(stderr, "%s: wrong channel argument\n", arg);
-                return 0;
-            }
-            int loglevel = parse_loglevel(argv[i + 2]);
-            if (loglevel < 0) {
-                fprintf(stderr, "%s: wrong loglevel argument\n", arg);
-                return 0;
-            }
-            options.loglevels[channel] = loglevel;
-            i += 2;
-        }
-        else if (!strcmp(arg, "--ssl")) {
-            options.ssl = 1;
-        }
-        else if (!strcmp(arg, "--nssdb")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.nssdb = argv[i + 1];
-            i++;
-        }
-        else if (!strcmp(arg, "--client-cert-name")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.client_cert_name = argv[i + 1];
-            i++;
-        }
-        else if (!strcmp(arg, "--server-name")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.server_name = argv[i + 1];
-            i++;
-        }
-        else if (!strcmp(arg, "--server-addr")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            options.server_addr = argv[i + 1];
-            i++;
-        }
-        else if (!strcmp(arg, "--flood-id")) {
-            if (1 >= argc - i) {
-                fprintf(stderr, "%s: requires an argument\n", arg);
-                return 0;
-            }
-            if (options.num_floods == MAX_FLOODS) {
-                fprintf(stderr, "%s: too many\n", arg);
-                return 0;
-            }
-            options.floods[options.num_floods] = atoi(argv[i + 1]);
-            options.num_floods++;
-            i++;
-        }
-        else {
-            fprintf(stderr, "unknown option: %s\n", arg);
-            return 0;
-        }
-    }
-    
-    if (options.help || options.version) {
-        return 1;
-    }
-    
-    if (options.ssl != !!options.nssdb) {
-        fprintf(stderr, "False: --ssl <=> --nssdb\n");
-        return 0;
-    }
-    
-    if (options.ssl != !!options.client_cert_name) {
-        fprintf(stderr, "False: --ssl <=> --client-cert-name\n");
-        return 0;
-    }
-    
-    if (!options.server_addr) {
-        fprintf(stderr, "False: --server-addr\n");
-        return 0;
-    }
-    
-    return 1;
-}
-
-int resolve_arguments (void)
-{
-    // resolve server address
-    ASSERT(options.server_addr)
-    if (!BAddr_Parse(&server_addr, options.server_addr, server_name, sizeof(server_name))) {
-        BLog(BLOG_ERROR, "server addr: BAddr_Parse failed");
-        return 0;
-    }
-    if (!addr_supported(server_addr)) {
-        BLog(BLOG_ERROR, "server addr: not supported");
-        return 0;
-    }
-    
-    // override server name if requested
-    if (options.server_name) {
-        if (strlen(options.server_name) >= sizeof(server_name)) {
-            BLog(BLOG_ERROR, "server name: too long");
-            return 0;
-        }
-        strcpy(server_name, options.server_name);
-    }
-    
-    return 1;
-}
-
-void signal_handler (void *unused)
-{
-    BLog(BLOG_NOTICE, "termination requested");
-    
-    terminate();
-}
-
-void server_handler_error (void *user)
-{
-    BLog(BLOG_ERROR, "server connection failed, exiting");
-    
-    terminate();
-}
-
-void server_handler_ready (void *user, peerid_t param_my_id, uint32_t ext_ip)
-{
-    ASSERT(!server_ready)
-    
-    // remember our ID
-    my_id = param_my_id;
-    
-    // init flooding
-    
-    // init source
-    PacketRecvInterface_Init(&flood_source, SC_MAX_ENC, flood_source_handler_recv, NULL, BReactor_PendingGroup(&ss));
-    
-    // init encoder
-    PacketProtoEncoder_Init(&flood_encoder, &flood_source, BReactor_PendingGroup(&ss));
-    
-    // init buffer
-    if (!SinglePacketBuffer_Init(&flood_buffer, PacketProtoEncoder_GetOutput(&flood_encoder), ServerConnection_GetSendInterface(&server), BReactor_PendingGroup(&ss))) {
-        BLog(BLOG_ERROR, "SinglePacketBuffer_Init failed, exiting");
-        goto fail1;
-    }
-    
-    // set not blocking
-    flood_blocking = 0;
-    
-    // set server ready
-    server_ready = 1;
-    
-    BLog(BLOG_INFO, "server: ready, my ID is %d", (int)my_id);
-    
-    return;
-    
-fail1:
-    PacketProtoEncoder_Free(&flood_encoder);
-    PacketRecvInterface_Free(&flood_source);
-    terminate();
-}
-
-void server_handler_newclient (void *user, peerid_t peer_id, int flags, const uint8_t *cert, int cert_len)
-{
-    ASSERT(server_ready)
-    
-    BLog(BLOG_INFO, "newclient %d", (int)peer_id);
-}
-
-void server_handler_endclient (void *user, peerid_t peer_id)
-{
-    ASSERT(server_ready)
-    
-    BLog(BLOG_INFO, "endclient %d", (int)peer_id);
-}
-
-void server_handler_message (void *user, peerid_t peer_id, uint8_t *data, int data_len)
-{
-    ASSERT(server_ready)
-    ASSERT(data_len >= 0)
-    ASSERT(data_len <= SC_MAX_MSGLEN)
-    
-    BLog(BLOG_INFO, "message from %d", (int)peer_id);
-}
-
-void flood_source_handler_recv (void *user, uint8_t *data)
-{
-    ASSERT(server_ready)
-    ASSERT(!flood_blocking)
-    if (options.num_floods > 0) {
-        ASSERT(flood_next >= 0)
-        ASSERT(flood_next < options.num_floods)
-    }
-    
-    if (options.num_floods == 0) {
-        flood_blocking = 1;
-        return;
-    }
-    
-    peerid_t peer_id = options.floods[flood_next];
-    flood_next = (flood_next + 1) % options.num_floods;
-    
-    BLog(BLOG_INFO, "message to %d", (int)peer_id);
-    
-    struct sc_header header;
-    header.type = SCID_OUTMSG;
-    memcpy(data, &header, sizeof(header));
-    
-    struct sc_client_outmsg omsg;
-    omsg.clientid = htol16(peer_id);
-    memcpy(data + sizeof(header), &omsg, sizeof(omsg));
-    
-    memset(data + sizeof(struct sc_header) + sizeof(struct sc_client_outmsg), 0, SC_MAX_MSGLEN);
-    
-    PacketRecvInterface_Done(&flood_source, sizeof(struct sc_header) + sizeof(struct sc_client_outmsg) + SC_MAX_MSGLEN);
-}
diff --git a/external/badvpn_dns/flooder/flooder.h b/external/badvpn_dns/flooder/flooder.h
deleted file mode 100644
index c8b8443..0000000
--- a/external/badvpn_dns/flooder/flooder.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * @file flooder.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-// name of the program
-#define PROGRAM_NAME "flooder"
-
-// server output buffer size
-#define SERVER_BUFFER_MIN_PACKETS 200
-
-// maximum number of peers to flood
-#define MAX_FLOODS 64
diff --git a/external/badvpn_dns/flow/BufferWriter.c b/external/badvpn_dns/flow/BufferWriter.c
deleted file mode 100644
index b0e4129..0000000
--- a/external/badvpn_dns/flow/BufferWriter.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * @file BufferWriter.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <misc/debug.h>
-
-#include <flow/BufferWriter.h>
-
-static void output_handler_recv (BufferWriter *o, uint8_t *data)
-{
-    ASSERT(!o->out_have)
-    
-    // set output packet
-    o->out_have = 1;
-    o->out = data;
-}
-
-void BufferWriter_Init (BufferWriter *o, int mtu, BPendingGroup *pg)
-{
-    ASSERT(mtu >= 0)
-    
-    // init output
-    PacketRecvInterface_Init(&o->recv_interface, mtu, (PacketRecvInterface_handler_recv)output_handler_recv, o, pg);
-    
-    // set no output packet
-    o->out_have = 0;
-    
-    DebugObject_Init(&o->d_obj);
-    #ifndef NDEBUG
-    o->d_mtu = mtu;
-    o->d_writing = 0;
-    #endif
-}
-
-void BufferWriter_Free (BufferWriter *o)
-{
-    DebugObject_Free(&o->d_obj);
-    
-    // free output
-    PacketRecvInterface_Free(&o->recv_interface);
-}
-
-PacketRecvInterface * BufferWriter_GetOutput (BufferWriter *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->recv_interface;
-}
-
-int BufferWriter_StartPacket (BufferWriter *o, uint8_t **buf)
-{
-    ASSERT(!o->d_writing)
-    DebugObject_Access(&o->d_obj);
-    
-    if (!o->out_have) {
-        return 0;
-    }
-    
-    if (buf) {
-        *buf = o->out;
-    }
-    
-    #ifndef NDEBUG
-    o->d_writing = 1;
-    #endif
-    
-    return 1;
-}
-
-void BufferWriter_EndPacket (BufferWriter *o, int len)
-{
-    ASSERT(len >= 0)
-    ASSERT(len <= o->d_mtu)
-    ASSERT(o->out_have)
-    ASSERT(o->d_writing)
-    DebugObject_Access(&o->d_obj);
-    
-    // set no output packet
-    o->out_have = 0;
-    
-    // finish packet
-    PacketRecvInterface_Done(&o->recv_interface, len);
-    
-    #ifndef NDEBUG
-    o->d_writing = 0;
-    #endif
-}
diff --git a/external/badvpn_dns/flow/BufferWriter.h b/external/badvpn_dns/flow/BufferWriter.h
deleted file mode 100644
index 6b6a9c4..0000000
--- a/external/badvpn_dns/flow/BufferWriter.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * @file BufferWriter.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Object for writing packets to a {@link PacketRecvInterface} client
- * in a best-effort fashion.
- */
-
-#ifndef BADVPN_FLOW_BUFFERWRITER_H
-#define BADVPN_FLOW_BUFFERWRITER_H
-
-#include <stdint.h>
-
-#include <misc/debug.h>
-#include <base/DebugObject.h>
-#include <flow/PacketRecvInterface.h>
-
-/**
- * Object for writing packets to a {@link PacketRecvInterface} client
- * in a best-effort fashion.
- */
-typedef struct {
-    PacketRecvInterface recv_interface;
-    int out_have;
-    uint8_t *out;
-    DebugObject d_obj;
-    #ifndef NDEBUG
-    int d_mtu;
-    int d_writing;
-    #endif
-} BufferWriter;
-
-/**
- * Initializes the object.
- * The object is initialized in not writing state.
- *
- * @param o the object
- * @param mtu maximum input packet length
- * @param pg pending group
- */
-void BufferWriter_Init (BufferWriter *o, int mtu, BPendingGroup *pg);
-
-/**
- * Frees the object.
- *
- * @param o the object
- */
-void BufferWriter_Free (BufferWriter *o);
-
-/**
- * Returns the output interface.
- *
- * @param o the object
- * @return output interface
- */
-PacketRecvInterface * BufferWriter_GetOutput (BufferWriter *o);
-
-/**
- * Attempts to provide a memory location for writing a packet.
- * The object must be in not writing state.
- * On success, the object enters writing state.
- * 
- * @param o the object
- * @param buf if not NULL, on success, the memory location will be stored here.
- *            It will have space for MTU bytes.
- * @return 1 on success, 0 on failure
- */
-int BufferWriter_StartPacket (BufferWriter *o, uint8_t **buf) WARN_UNUSED;
-
-/**
- * Submits a packet written to the buffer.
- * The object must be in writing state.
- * Yhe object enters not writing state.
- * 
- * @param o the object
- * @param len length of the packet that was written. Must be >=0 and
- *            <=MTU.
- */
-void BufferWriter_EndPacket (BufferWriter *o, int len);
-
-#endif
diff --git a/external/badvpn_dns/flow/CMakeLists.txt b/external/badvpn_dns/flow/CMakeLists.txt
deleted file mode 100644
index 6cd82f6..0000000
--- a/external/badvpn_dns/flow/CMakeLists.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-set(FLOW_SOURCES
-    PacketPassFairQueue.c
-    PacketPassPriorityQueue.c
-    PacketPassConnector.c
-    PacketRecvConnector.c
-    StreamRecvConnector.c
-    PacketRecvBlocker.c
-    PacketPassNotifier.c
-    PacketBuffer.c
-    SinglePacketBuffer.c
-    PacketCopier.c
-    PacketStreamSender.c
-    PacketProtoEncoder.c
-    PacketProtoDecoder.c
-    PacketProtoFlow.c
-    SinglePacketSender.c
-    BufferWriter.c
-    PacketPassInterface.c
-    PacketRecvInterface.c
-    StreamPassInterface.c
-    StreamRecvInterface.c
-    RouteBuffer.c
-    PacketRouter.c
-    LineBuffer.c
-    SingleStreamSender.c
-    SingleStreamReceiver.c
-    StreamPacketSender.c
-    StreamPassConnector.c
-    PacketPassFifoQueue.c
-)
-badvpn_add_library(flow "base" "" "${FLOW_SOURCES}")
diff --git a/external/badvpn_dns/flow/LineBuffer.c b/external/badvpn_dns/flow/LineBuffer.c
deleted file mode 100644
index 15c9969..0000000
--- a/external/badvpn_dns/flow/LineBuffer.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/**
- * @file LineBuffer.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <base/BLog.h>
-
-#include <flow/LineBuffer.h>
-
-#include <generated/blog_channel_LineBuffer.h>
-
-static void input_handler_done (LineBuffer *o, int data_len)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(data_len > 0)
-    ASSERT(data_len <= o->buf_size - o->buf_used)
-    
-    // update buffer
-    o->buf_used += data_len;
-    
-    // look for newline
-    int i;
-    for (i = o->buf_used - data_len; i < o->buf_used; i++) {
-        if (o->buf[i] == o->nl_char) {
-            break;
-        }
-    }
-    
-    if (i < o->buf_used || o->buf_used == o->buf_size) {
-        if (i == o->buf_used) {
-            BLog(BLOG_WARNING, "line too long");
-        }
-        
-        // pass to output
-        o->buf_consumed = (i < o->buf_used ? i + 1 : i);
-        PacketPassInterface_Sender_Send(o->output, o->buf, o->buf_consumed);
-    } else {
-        // receive more data
-        StreamRecvInterface_Receiver_Recv(o->input, o->buf + o->buf_used, o->buf_size - o->buf_used);
-    }
-}
-
-static void output_handler_done (LineBuffer *o)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->buf_consumed > 0)
-    ASSERT(o->buf_consumed <= o->buf_used)
-    
-    // update buffer
-    memmove(o->buf, o->buf + o->buf_consumed, o->buf_used - o->buf_consumed);
-    o->buf_used -= o->buf_consumed;
-    
-    // look for newline
-    int i;
-    for (i = 0; i < o->buf_used; i++) {
-        if (o->buf[i] == o->nl_char) {
-            break;
-        }
-    }
-    
-    if (i < o->buf_used || o->buf_used == o->buf_size) {
-        // pass to output
-        o->buf_consumed = (i < o->buf_used ? i + 1 : i);
-        PacketPassInterface_Sender_Send(o->output, o->buf, o->buf_consumed);
-    } else {
-        // receive more data
-        StreamRecvInterface_Receiver_Recv(o->input, o->buf + o->buf_used, o->buf_size - o->buf_used);
-    }
-}
-
-int LineBuffer_Init (LineBuffer *o, StreamRecvInterface *input, PacketPassInterface *output, int buf_size, uint8_t nl_char)
-{
-    ASSERT(buf_size > 0)
-    ASSERT(PacketPassInterface_GetMTU(output) >= buf_size)
-    
-    // init arguments
-    o->input = input;
-    o->output = output;
-    o->buf_size = buf_size;
-    o->nl_char = nl_char;
-    
-    // init input
-    StreamRecvInterface_Receiver_Init(o->input, (StreamRecvInterface_handler_done)input_handler_done, o);
-    
-    // init output
-    PacketPassInterface_Sender_Init(o->output, (PacketPassInterface_handler_done)output_handler_done, o);
-    
-    // set buffer empty
-    o->buf_used = 0;
-    
-    // allocate buffer
-    if (!(o->buf = (uint8_t *)malloc(o->buf_size))) {
-        BLog(BLOG_ERROR, "malloc failed");
-        goto fail0;
-    }
-    
-    // start receiving
-    StreamRecvInterface_Receiver_Recv(o->input, o->buf, o->buf_size);
-    
-    DebugObject_Init(&o->d_obj);
-    return 1;
-    
-fail0:
-    return 0;
-}
-
-void LineBuffer_Free (LineBuffer *o)
-{
-    DebugObject_Free(&o->d_obj);
-    
-    // free buffer
-    free(o->buf);
-}
diff --git a/external/badvpn_dns/flow/LineBuffer.h b/external/badvpn_dns/flow/LineBuffer.h
deleted file mode 100644
index 6e15e32..0000000
--- a/external/badvpn_dns/flow/LineBuffer.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * @file LineBuffer.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef BADVPN_FLOW_LINEBUFFER_H
-#define BADVPN_FLOW_LINEBUFFER_H
-
-#include <stdint.h>
-
-#include <misc/debug.h>
-#include <base/DebugObject.h>
-#include <flow/StreamRecvInterface.h>
-#include <flow/PacketPassInterface.h>
-
-typedef struct {
-    StreamRecvInterface *input;
-    PacketPassInterface *output;
-    int buf_size;
-    uint8_t nl_char;
-    int buf_used;
-    uint8_t *buf;
-    int buf_consumed;
-    DebugObject d_obj;
-} LineBuffer;
-
-int LineBuffer_Init (LineBuffer *o, StreamRecvInterface *input, PacketPassInterface *output, int buf_size, uint8_t nl_char) WARN_UNUSED;
-void LineBuffer_Free (LineBuffer *o);
-
-#endif
diff --git a/external/badvpn_dns/flow/PacketBuffer.c b/external/badvpn_dns/flow/PacketBuffer.c
deleted file mode 100644
index 30afef6..0000000
--- a/external/badvpn_dns/flow/PacketBuffer.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * @file PacketBuffer.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-
-#include <misc/debug.h>
-#include <misc/balloc.h>
-
-#include <flow/PacketBuffer.h>
-
-static void input_handler_done (PacketBuffer *buf, int in_len);
-static void output_handler_done (PacketBuffer *buf);
-
-void input_handler_done (PacketBuffer *buf, int in_len)
-{
-    ASSERT(in_len >= 0)
-    ASSERT(in_len <= buf->input_mtu)
-    DebugObject_Access(&buf->d_obj);
-    
-    // remember if buffer is empty
-    int was_empty = (buf->buf.output_avail < 0);
-    
-    // submit packet to buffer
-    ChunkBuffer2_SubmitPacket(&buf->buf, in_len);
-    
-    // if there is space, schedule receive
-    if (buf->buf.input_avail >= buf->input_mtu) {
-        PacketRecvInterface_Receiver_Recv(buf->input, buf->buf.input_dest);
-    }
-    
-    // if buffer was empty, schedule send
-    if (was_empty) {
-        PacketPassInterface_Sender_Send(buf->output, buf->buf.output_dest, buf->buf.output_avail);
-    }
-}
-
-void output_handler_done (PacketBuffer *buf)
-{
-    DebugObject_Access(&buf->d_obj);
-    
-    // remember if buffer is full
-    int was_full = (buf->buf.input_avail < buf->input_mtu);
-    
-    // remove packet from buffer
-    ChunkBuffer2_ConsumePacket(&buf->buf);
-    
-    // if buffer was full and there is space, schedule receive
-    if (was_full && buf->buf.input_avail >= buf->input_mtu) {
-        PacketRecvInterface_Receiver_Recv(buf->input, buf->buf.input_dest);
-    }
-    
-    // if there is more data, schedule send
-    if (buf->buf.output_avail >= 0) {
-        PacketPassInterface_Sender_Send(buf->output, buf->buf.output_dest, buf->buf.output_avail);
-    }
-}
-
-int PacketBuffer_Init (PacketBuffer *buf, PacketRecvInterface *input, PacketPassInterface *output, int num_packets, BPendingGroup *pg)
-{
-    ASSERT(PacketPassInterface_GetMTU(output) >= PacketRecvInterface_GetMTU(input))
-    ASSERT(num_packets > 0)
-    
-    // init arguments
-    buf->input = input;
-    buf->output = output;
-    
-    // init input
-    PacketRecvInterface_Receiver_Init(buf->input, (PacketRecvInterface_handler_done)input_handler_done, buf);
-    
-    // set input MTU
-    buf->input_mtu = PacketRecvInterface_GetMTU(buf->input);
-    
-    // init output
-    PacketPassInterface_Sender_Init(buf->output, (PacketPassInterface_handler_done)output_handler_done, buf);
-    
-    // allocate buffer
-    int num_blocks = ChunkBuffer2_calc_blocks(buf->input_mtu, num_packets);
-    if (num_blocks < 0) {
-        goto fail0;
-    }
-    if (!(buf->buf_data = (struct ChunkBuffer2_block *)BAllocArray(num_blocks, sizeof(buf->buf_data[0])))) {
-        goto fail0;
-    }
-    
-    // init buffer
-    ChunkBuffer2_Init(&buf->buf, buf->buf_data, num_blocks, buf->input_mtu);
-    
-    // schedule receive
-    PacketRecvInterface_Receiver_Recv(buf->input, buf->buf.input_dest);
-    
-    DebugObject_Init(&buf->d_obj);
-    
-    return 1;
-    
-fail0:
-    return 0;
-}
-
-void PacketBuffer_Free (PacketBuffer *buf)
-{
-    DebugObject_Free(&buf->d_obj);
-    
-    // free buffer
-    BFree(buf->buf_data);
-}
diff --git a/external/badvpn_dns/flow/PacketBuffer.h b/external/badvpn_dns/flow/PacketBuffer.h
deleted file mode 100644
index 6daab69..0000000
--- a/external/badvpn_dns/flow/PacketBuffer.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * @file PacketBuffer.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Packet buffer with {@link PacketRecvInterface} input and {@link PacketPassInterface} output.
- */
-
-#ifndef BADVPN_FLOW_PACKETBUFFER_H
-#define BADVPN_FLOW_PACKETBUFFER_H
-
-#include <stdint.h>
-
-#include <misc/debug.h>
-#include <base/DebugObject.h>
-#include <structure/ChunkBuffer2.h>
-#include <flow/PacketRecvInterface.h>
-#include <flow/PacketPassInterface.h>
-
-/**
- * Packet buffer with {@link PacketRecvInterface} input and {@link PacketPassInterface} output.
- */
-typedef struct {
-    DebugObject d_obj;
-    PacketRecvInterface *input;
-    int input_mtu;
-    PacketPassInterface *output;
-    struct ChunkBuffer2_block *buf_data;
-    ChunkBuffer2 buf;
-} PacketBuffer;
-
-/**
- * Initializes the buffer.
- * Output MTU must be >= input MTU.
- *
- * @param buf the object
- * @param input input interface
- * @param output output interface
- * @param num_packets minimum number of packets the buffer must hold. Must be >0.
- * @param pg pending group
- * @return 1 on success, 0 on failure
- */
-int PacketBuffer_Init (PacketBuffer *buf, PacketRecvInterface *input, PacketPassInterface *output, int num_packets, BPendingGroup *pg) WARN_UNUSED;
-
-/**
- * Frees the buffer.
- *
- * @param buf the object
- */
-void PacketBuffer_Free (PacketBuffer *buf);
-
-#endif
diff --git a/external/badvpn_dns/flow/PacketCopier.c b/external/badvpn_dns/flow/PacketCopier.c
deleted file mode 100644
index f4c7126..0000000
--- a/external/badvpn_dns/flow/PacketCopier.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/**
- * @file PacketCopier.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <string.h>
-
-#include <misc/debug.h>
-
-#include <flow/PacketCopier.h>
-
-static void input_handler_send (PacketCopier *o, uint8_t *data, int data_len)
-{
-    ASSERT(o->in_len == -1)
-    ASSERT(data_len >= 0)
-    DebugObject_Access(&o->d_obj);
-    
-    if (!o->out_have) {
-        o->in_len = data_len;
-        o->in = data;
-        return;
-    }
-    
-    memcpy(o->out, data, data_len);
-    
-    // finish input packet
-    PacketPassInterface_Done(&o->input);
-    
-    // finish output packet
-    PacketRecvInterface_Done(&o->output, data_len);
-    
-    o->out_have = 0;
-}
-
-static void input_handler_requestcancel (PacketCopier *o)
-{
-    ASSERT(o->in_len >= 0)
-    ASSERT(!o->out_have)
-    DebugObject_Access(&o->d_obj);
-    
-    // finish input packet
-    PacketPassInterface_Done(&o->input);
-    
-    o->in_len = -1;
-}
-
-static void output_handler_recv (PacketCopier *o, uint8_t *data)
-{
-    ASSERT(!o->out_have)
-    DebugObject_Access(&o->d_obj);
-    
-    if (o->in_len < 0) {
-        o->out_have = 1;
-        o->out = data;
-        return;
-    }
-    
-    memcpy(data, o->in, o->in_len);
-    
-    // finish input packet
-    PacketPassInterface_Done(&o->input);
-    
-    // finish output packet
-    PacketRecvInterface_Done(&o->output, o->in_len);
-    
-    o->in_len = -1;
-}
-
-void PacketCopier_Init (PacketCopier *o, int mtu, BPendingGroup *pg)
-{
-    ASSERT(mtu >= 0)
-    
-    // init input
-    PacketPassInterface_Init(&o->input, mtu, (PacketPassInterface_handler_send)input_handler_send, o, pg);
-    PacketPassInterface_EnableCancel(&o->input, (PacketPassInterface_handler_requestcancel)input_handler_requestcancel);
-    
-    // init output
-    PacketRecvInterface_Init(&o->output, mtu, (PacketRecvInterface_handler_recv)output_handler_recv, o, pg);
-    
-    // set no input packet
-    o->in_len = -1;
-    
-    // set no output packet
-    o->out_have = 0;
-    
-    DebugObject_Init(&o->d_obj);
-}
-
-void PacketCopier_Free (PacketCopier *o)
-{
-    DebugObject_Free(&o->d_obj);
-
-    // free output
-    PacketRecvInterface_Free(&o->output);
-    
-    // free input
-    PacketPassInterface_Free(&o->input);
-}
-
-PacketPassInterface * PacketCopier_GetInput (PacketCopier *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->input;
-}
-
-PacketRecvInterface * PacketCopier_GetOutput (PacketCopier *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->output;
-}
diff --git a/external/badvpn_dns/flow/PacketCopier.h b/external/badvpn_dns/flow/PacketCopier.h
deleted file mode 100644
index 9b8ba86..0000000
--- a/external/badvpn_dns/flow/PacketCopier.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * @file PacketCopier.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Object which copies packets.
- */
-
-#ifndef BADVPN_FLOW_PACKETCOPIER_H
-#define BADVPN_FLOW_PACKETCOPIER_H
-
-#include <stdint.h>
-
-#include <flow/PacketPassInterface.h>
-#include <flow/PacketRecvInterface.h>
-
-/**
- * Object which copies packets.
- * Input is via {@link PacketPassInterface}.
- * Output is via {@link PacketRecvInterface}.
- */
-typedef struct {
-    DebugObject d_obj;
-    PacketPassInterface input;
-    PacketRecvInterface output;
-    int in_len;
-    uint8_t *in;
-    int out_have;
-    uint8_t *out;
-} PacketCopier;
-
-/**
- * Initializes the object.
- * 
- * @param o the object
- * @param mtu maximum packet size. Must be >=0.
- * @param pg pending group
- */
-void PacketCopier_Init (PacketCopier *o, int mtu, BPendingGroup *pg);
-
-/**
- * Frees the object.
- * 
- * @param o the object
- */
-void PacketCopier_Free (PacketCopier *o);
-
-/**
- * Returns the input interface.
- * The MTU of the interface will as in {@link PacketCopier_Init}.
- * The interface will support cancel functionality.
- * 
- * @return input interface
- */
-PacketPassInterface * PacketCopier_GetInput (PacketCopier *o);
-
-/**
- * Returns the output interface.
- * The MTU of the interface will be as in {@link PacketCopier_Init}.
- * 
- * @return output interface
- */
-PacketRecvInterface * PacketCopier_GetOutput (PacketCopier *o);
-
-#endif
diff --git a/external/badvpn_dns/flow/PacketPassConnector.c b/external/badvpn_dns/flow/PacketPassConnector.c
deleted file mode 100644
index 1a10326..0000000
--- a/external/badvpn_dns/flow/PacketPassConnector.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/**
- * @file PacketPassConnector.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stddef.h>
-
-#include <misc/debug.h>
-
-#include <flow/PacketPassConnector.h>
-
-static void input_handler_send (PacketPassConnector *o, uint8_t *data, int data_len)
-{
-    ASSERT(data_len >= 0)
-    ASSERT(data_len <= o->input_mtu)
-    ASSERT(o->in_len == -1)
-    DebugObject_Access(&o->d_obj);
-    
-    // remember input packet
-    o->in_len = data_len;
-    o->in = data;
-    
-    if (o->output) {
-        // schedule send
-        PacketPassInterface_Sender_Send(o->output, o->in, o->in_len);
-    }
-}
-
-static void output_handler_done (PacketPassConnector *o)
-{
-    ASSERT(o->in_len >= 0)
-    ASSERT(o->output)
-    DebugObject_Access(&o->d_obj);
-    
-    // have no input packet
-    o->in_len = -1;
-    
-    // allow input to send more packets
-    PacketPassInterface_Done(&o->input);
-}
-
-void PacketPassConnector_Init (PacketPassConnector *o, int mtu, BPendingGroup *pg)
-{
-    ASSERT(mtu >= 0)
-    
-    // init arguments
-    o->input_mtu = mtu;
-    
-    // init input
-    PacketPassInterface_Init(&o->input, o->input_mtu, (PacketPassInterface_handler_send)input_handler_send, o, pg);
-    
-    // have no input packet
-    o->in_len = -1;
-    
-    // have no output
-    o->output = NULL;
-    
-    DebugObject_Init(&o->d_obj);
-}
-
-void PacketPassConnector_Free (PacketPassConnector *o)
-{
-    DebugObject_Free(&o->d_obj);
-    
-    // free input
-    PacketPassInterface_Free(&o->input);
-}
-
-PacketPassInterface * PacketPassConnector_GetInput (PacketPassConnector *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return &o->input;
-}
-
-void PacketPassConnector_ConnectOutput (PacketPassConnector *o, PacketPassInterface *output)
-{
-    ASSERT(!o->output)
-    ASSERT(PacketPassInterface_GetMTU(output) >= o->input_mtu)
-    DebugObject_Access(&o->d_obj);
-    
-    // set output
-    o->output = output;
-    
-    // init output
-    PacketPassInterface_Sender_Init(o->output, (PacketPassInterface_handler_done)output_handler_done, o);
-    
-    // if we have an input packet, schedule send
-    if (o->in_len >= 0) {
-        PacketPassInterface_Sender_Send(o->output, o->in, o->in_len);
-    }
-}
-
-void PacketPassConnector_DisconnectOutput (PacketPassConnector *o)
-{
-    ASSERT(o->output)
-    DebugObject_Access(&o->d_obj);
-    
-    // set no output
-    o->output = NULL;
-}
diff --git a/external/badvpn_dns/flow/PacketPassConnector.h b/external/badvpn_dns/flow/PacketPassConnector.h
deleted file mode 100644
index 1a2cc6c..0000000
--- a/external/badvpn_dns/flow/PacketPassConnector.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * @file PacketPassConnector.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * A {@link PacketPassInterface} layer which allows the output to be
- * connected and disconnected on the fly.
- */
-
-#ifndef BADVPN_FLOW_PACKETPASSCONNECTOR_H
-#define BADVPN_FLOW_PACKETPASSCONNECTOR_H
-
-#include <stdint.h>
-
-#include <base/DebugObject.h>
-#include <flow/PacketPassInterface.h>
-
-/**
- * A {@link PacketPassInterface} layer which allows the output to be
- * connected and disconnected on the fly.
- */
-typedef struct {
-    PacketPassInterface input;
-    int input_mtu;
-    int in_len;
-    uint8_t *in;
-    PacketPassInterface *output;
-    DebugObject d_obj;
-} PacketPassConnector;
-
-/**
- * Initializes the object.
- * The object is initialized in not connected state.
- *
- * @param o the object
- * @param mtu maximum input packet size. Must be >=0.
- * @param pg pending group
- */
-void PacketPassConnector_Init (PacketPassConnector *o, int mtu, BPendingGroup *pg);
-
-/**
- * Frees the object.
- *
- * @param o the object
- */
-void PacketPassConnector_Free (PacketPassConnector *o);
-
-/**
- * Returns the input interface.
- * The MTU of the interface will be as in {@link PacketPassConnector_Init}.
- *
- * @param o the object
- * @return input interface
- */
-PacketPassInterface * PacketPassConnector_GetInput (PacketPassConnector *o);
-
-/**
- * Connects output.
- * The object must be in not connected state.
- * The object enters connected state.
- *
- * @param o the object
- * @param output output to connect. Its MTU must be >= MTU specified in
- *               {@link PacketPassConnector_Init}.
- */
-void PacketPassConnector_ConnectOutput (PacketPassConnector *o, PacketPassInterface *output);
-
-/**
- * Disconnects output.
- * The object must be in connected state.
- * The object enters not connected state.
- *
- * @param o the object
- */
-void PacketPassConnector_DisconnectOutput (PacketPassConnector *o);
-
-#endif
diff --git a/external/badvpn_dns/flow/PacketPassFairQueue.c b/external/badvpn_dns/flow/PacketPassFairQueue.c
deleted file mode 100644
index bbfafe0..0000000
--- a/external/badvpn_dns/flow/PacketPassFairQueue.c
+++ /dev/null
@@ -1,405 +0,0 @@
-/**
- * @file PacketPassFairQueue.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-
-#include <misc/debug.h>
-#include <misc/offset.h>
-#include <misc/minmax.h>
-#include <misc/compare.h>
-
-#include <flow/PacketPassFairQueue.h>
-
-static int compare_flows (PacketPassFairQueueFlow *f1, PacketPassFairQueueFlow *f2)
-{
-    int cmp = B_COMPARE(f1->time, f2->time);
-    if (cmp) {
-        return cmp;
-    }
-    
-    return B_COMPARE((uintptr_t)f1, (uintptr_t)f2);
-}
-
-#include "PacketPassFairQueue_tree.h"
-#include <structure/SAvl_impl.h>
-
-static uint64_t get_current_time (PacketPassFairQueue *m)
-{
-    if (m->sending_flow) {
-        return m->sending_flow->time;
-    }
-    
-    uint64_t time = 0; // to remove warning
-    int have = 0;
-    
-    PacketPassFairQueueFlow *first_flow = PacketPassFairQueue__Tree_GetFirst(&m->queued_tree, 0);
-    if (first_flow) {
-        ASSERT(first_flow->is_queued)
-        
-        time = first_flow->time;
-        have = 1;
-    }
-    
-    if (m->previous_flow) {
-        if (!have || m->previous_flow->time < time) {
-            time = m->previous_flow->time;
-            have = 1;
-        }
-    }
-    
-    return (have ? time : 0);
-}
-
-static void increment_sent_flow (PacketPassFairQueueFlow *flow, uint64_t amount)
-{
-    PacketPassFairQueue *m = flow->m;
-    
-    ASSERT(amount <= FAIRQUEUE_MAX_TIME)
-    ASSERT(!flow->is_queued)
-    ASSERT(!m->sending_flow)
-    
-    // does time overflow?
-    if (amount > FAIRQUEUE_MAX_TIME - flow->time) {
-        // get time to subtract
-        uint64_t subtract;
-        PacketPassFairQueueFlow *first_flow = PacketPassFairQueue__Tree_GetFirst(&m->queued_tree, 0);
-        if (!first_flow) {
-            subtract = flow->time;
-        } else {
-            ASSERT(first_flow->is_queued)
-            subtract = first_flow->time;
-        }
-        
-        // subtract time from all flows
-        for (LinkedList1Node *list_node = LinkedList1_GetFirst(&m->flows_list); list_node; list_node = LinkedList1Node_Next(list_node)) {
-            PacketPassFairQueueFlow *someflow = UPPER_OBJECT(list_node, PacketPassFairQueueFlow, list_node);
-            
-            // don't subtract more time than there is, except for the just finished flow,
-            // where we allow time to underflow and then overflow to the correct value after adding to it
-            if (subtract > someflow->time && someflow != flow) {
-                ASSERT(!someflow->is_queued)
-                someflow->time = 0;
-            } else {
-                someflow->time -= subtract;
-            }
-        }
-    }
-    
-    // add time to flow
-    flow->time += amount;
-}
-
-static void schedule (PacketPassFairQueue *m)
-{
-    ASSERT(!m->sending_flow)
-    ASSERT(!m->previous_flow)
-    ASSERT(!m->freeing)
-    ASSERT(!PacketPassFairQueue__Tree_IsEmpty(&m->queued_tree))
-    
-    // get first queued flow
-    PacketPassFairQueueFlow *qflow = PacketPassFairQueue__Tree_GetFirst(&m->queued_tree, 0);
-    ASSERT(qflow->is_queued)
-    
-    // remove flow from queue
-    PacketPassFairQueue__Tree_Remove(&m->queued_tree, 0, qflow);
-    qflow->is_queued = 0;
-    
-    // schedule send
-    PacketPassInterface_Sender_Send(m->output, qflow->queued.data, qflow->queued.data_len);
-    m->sending_flow = qflow;
-    m->sending_len = qflow->queued.data_len;
-}
-
-static void schedule_job_handler (PacketPassFairQueue *m)
-{
-    ASSERT(!m->sending_flow)
-    ASSERT(!m->freeing)
-    DebugObject_Access(&m->d_obj);
-    
-    // remove previous flow
-    m->previous_flow = NULL;
-    
-    if (!PacketPassFairQueue__Tree_IsEmpty(&m->queued_tree)) {
-        schedule(m);
-    }
-}
-
-static void input_handler_send (PacketPassFairQueueFlow *flow, uint8_t *data, int data_len)
-{
-    PacketPassFairQueue *m = flow->m;
-    
-    ASSERT(flow != m->sending_flow)
-    ASSERT(!flow->is_queued)
-    ASSERT(!m->freeing)
-    DebugObject_Access(&flow->d_obj);
-    
-    if (flow == m->previous_flow) {
-        // remove from previous flow
-        m->previous_flow = NULL;
-    } else {
-        // raise time
-        flow->time = bmax_uint64(flow->time, get_current_time(m));
-    }
-    
-    // queue flow
-    flow->queued.data = data;
-    flow->queued.data_len = data_len;
-    int res = PacketPassFairQueue__Tree_Insert(&m->queued_tree, 0, flow, NULL);
-    ASSERT_EXECUTE(res)
-    flow->is_queued = 1;
-    
-    if (!m->sending_flow && !BPending_IsSet(&m->schedule_job)) {
-        schedule(m);
-    }
-}
-
-static void output_handler_done (PacketPassFairQueue *m)
-{
-    ASSERT(m->sending_flow)
-    ASSERT(!m->previous_flow)
-    ASSERT(!BPending_IsSet(&m->schedule_job))
-    ASSERT(!m->freeing)
-    ASSERT(!m->sending_flow->is_queued)
-    
-    PacketPassFairQueueFlow *flow = m->sending_flow;
-    
-    // sending finished
-    m->sending_flow = NULL;
-    
-    // remember this flow so the schedule job can remove its time if it didn's send
-    m->previous_flow = flow;
-    
-    // update flow time by packet size
-    increment_sent_flow(flow, (uint64_t)m->packet_weight + m->sending_len);
-    
-    // schedule schedule
-    BPending_Set(&m->schedule_job);
-    
-    // finish flow packet
-    PacketPassInterface_Done(&flow->input);
-    
-    // call busy handler if set
-    if (flow->handler_busy) {
-        // handler is one-shot, unset it before calling
-        PacketPassFairQueue_handler_busy handler = flow->handler_busy;
-        flow->handler_busy = NULL;
-        
-        // call handler
-        handler(flow->user);
-        return;
-    }
-}
-
-int PacketPassFairQueue_Init (PacketPassFairQueue *m, PacketPassInterface *output, BPendingGroup *pg, int use_cancel, int packet_weight)
-{
-    ASSERT(packet_weight > 0)
-    ASSERT(use_cancel == 0 || use_cancel == 1)
-    ASSERT(!use_cancel || PacketPassInterface_HasCancel(output))
-    
-    // init arguments
-    m->output = output;
-    m->pg = pg;
-    m->use_cancel = use_cancel;
-    m->packet_weight = packet_weight;
-    
-    // make sure that (output MTU + packet_weight <= FAIRQUEUE_MAX_TIME)
-    if (!(
-        (PacketPassInterface_GetMTU(output) <= FAIRQUEUE_MAX_TIME) &&
-        (packet_weight <= FAIRQUEUE_MAX_TIME - PacketPassInterface_GetMTU(output))
-    )) {
-        goto fail0;
-    }
-    
-    // init output
-    PacketPassInterface_Sender_Init(m->output, (PacketPassInterface_handler_done)output_handler_done, m);
-    
-    // not sending
-    m->sending_flow = NULL;
-    
-    // no previous flow
-    m->previous_flow = NULL;
-    
-    // init queued tree
-    PacketPassFairQueue__Tree_Init(&m->queued_tree);
-    
-    // init flows list
-    LinkedList1_Init(&m->flows_list);
-    
-    // not freeing
-    m->freeing = 0;
-    
-    // init schedule job
-    BPending_Init(&m->schedule_job, m->pg, (BPending_handler)schedule_job_handler, m);
-    
-    DebugObject_Init(&m->d_obj);
-    DebugCounter_Init(&m->d_ctr);
-    return 1;
-    
-fail0:
-    return 0;
-}
-
-void PacketPassFairQueue_Free (PacketPassFairQueue *m)
-{
-    ASSERT(LinkedList1_IsEmpty(&m->flows_list))
-    ASSERT(PacketPassFairQueue__Tree_IsEmpty(&m->queued_tree))
-    ASSERT(!m->previous_flow)
-    ASSERT(!m->sending_flow)
-    DebugCounter_Free(&m->d_ctr);
-    DebugObject_Free(&m->d_obj);
-    
-    // free schedule job
-    BPending_Free(&m->schedule_job);
-}
-
-void PacketPassFairQueue_PrepareFree (PacketPassFairQueue *m)
-{
-    DebugObject_Access(&m->d_obj);
-    
-    // set freeing
-    m->freeing = 1;
-}
-
-int PacketPassFairQueue_GetMTU (PacketPassFairQueue *m)
-{
-    DebugObject_Access(&m->d_obj);
-    
-    return PacketPassInterface_GetMTU(m->output);
-}
-
-void PacketPassFairQueueFlow_Init (PacketPassFairQueueFlow *flow, PacketPassFairQueue *m)
-{
-    ASSERT(!m->freeing)
-    DebugObject_Access(&m->d_obj);
-    
-    // init arguments
-    flow->m = m;
-    
-    // have no canfree handler
-    flow->handler_busy = NULL;
-    
-    // init input
-    PacketPassInterface_Init(&flow->input, PacketPassInterface_GetMTU(flow->m->output), (PacketPassInterface_handler_send)input_handler_send, flow, m->pg);
-    
-    // set time
-    flow->time = 0;
-    
-    // add to flows list
-    LinkedList1_Append(&m->flows_list, &flow->list_node);
-    
-    // is not queued
-    flow->is_queued = 0;
-    
-    DebugObject_Init(&flow->d_obj);
-    DebugCounter_Increment(&m->d_ctr);
-}
-
-void PacketPassFairQueueFlow_Free (PacketPassFairQueueFlow *flow)
-{
-    PacketPassFairQueue *m = flow->m;
-    
-    ASSERT(m->freeing || flow != m->sending_flow)
-    DebugCounter_Decrement(&m->d_ctr);
-    DebugObject_Free(&flow->d_obj);
-    
-    // remove from current flow
-    if (flow == m->sending_flow) {
-        m->sending_flow = NULL;
-    }
-    
-    // remove from previous flow
-    if (flow == m->previous_flow) {
-        m->previous_flow = NULL;
-    }
-    
-    // remove from queue
-    if (flow->is_queued) {
-        PacketPassFairQueue__Tree_Remove(&m->queued_tree, 0, flow);
-    }
-    
-    // remove from flows list
-    LinkedList1_Remove(&m->flows_list, &flow->list_node);
-    
-    // free input
-    PacketPassInterface_Free(&flow->input);
-}
-
-void PacketPassFairQueueFlow_AssertFree (PacketPassFairQueueFlow *flow)
-{
-    PacketPassFairQueue *m = flow->m;
-    B_USE(m)
-    
-    ASSERT(m->freeing || flow != m->sending_flow)
-    DebugObject_Access(&flow->d_obj);
-}
-
-int PacketPassFairQueueFlow_IsBusy (PacketPassFairQueueFlow *flow)
-{
-    PacketPassFairQueue *m = flow->m;
-    
-    ASSERT(!m->freeing)
-    DebugObject_Access(&flow->d_obj);
-    
-    return (flow == m->sending_flow);
-}
-
-void PacketPassFairQueueFlow_RequestCancel (PacketPassFairQueueFlow *flow)
-{
-    PacketPassFairQueue *m = flow->m;
-    
-    ASSERT(flow == m->sending_flow)
-    ASSERT(m->use_cancel)
-    ASSERT(!m->freeing)
-    ASSERT(!BPending_IsSet(&m->schedule_job))
-    DebugObject_Access(&flow->d_obj);
-    
-    // request cancel
-    PacketPassInterface_Sender_RequestCancel(m->output);
-}
-
-void PacketPassFairQueueFlow_SetBusyHandler (PacketPassFairQueueFlow *flow, PacketPassFairQueue_handler_busy handler, void *user)
-{
-    PacketPassFairQueue *m = flow->m;
-    B_USE(m)
-    
-    ASSERT(flow == m->sending_flow)
-    ASSERT(!m->freeing)
-    DebugObject_Access(&flow->d_obj);
-    
-    // set handler
-    flow->handler_busy = handler;
-    flow->user = user;
-}
-
-PacketPassInterface * PacketPassFairQueueFlow_GetInput (PacketPassFairQueueFlow *flow)
-{
-    DebugObject_Access(&flow->d_obj);
-    
-    return &flow->input;
-}
diff --git a/external/badvpn_dns/flow/PacketPassFairQueue.h b/external/badvpn_dns/flow/PacketPassFairQueue.h
deleted file mode 100644
index f846596..0000000
--- a/external/badvpn_dns/flow/PacketPassFairQueue.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/**
- * @file PacketPassFairQueue.h
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the
- *    names of its contributors may be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * @section DESCRIPTION
- * 
- * Fair queue using {@link PacketPassInterface}.
- */
-
-#ifndef BADVPN_FLOW_PACKETPASSFAIRQUEUE_H
-#define BADVPN_FLOW_PACKETPASSFAIRQUEUE_H
-
-#include <stdint.h>
-
-#include <misc/debug.h>
-#include <misc/debugcounter.h>
-#include <structure/SAvl.h>
-#include <structure/LinkedList1.h>
-#include <base/DebugObject.h>
-#include <base/BPending.h>
-#include <flow/PacketPassInterface.h>
-
-// reduce this to test time overflow handling
-#define FAIRQUEUE_MAX_TIME UINT64_MAX
-
-typedef void (*PacketPassFairQueue_handler_busy) (void *user);
-
-struct PacketPassFairQueueFlow_s;
-
-#include "PacketPassFairQueue_tree.h"
-#include <structure/SAvl_decl.h>
-
-typedef struct PacketPassFairQueueFlow_s {
-    struct PacketPassFairQueue_s *m;
-    PacketPassFairQueue_handler_busy handler_busy;
-    void *user;
-    PacketPassInterface input;
-    uint64_t time;
-    LinkedList1Node list_node;
-    int is_queued;
-    struct {
-        PacketPassFairQueue__TreeNode tree_node;
-        uint8_t *data;
-        int data_len;
-    } queued;
-    DebugObject d_obj;
-} PacketPassFairQueueFlow;
-
-/**
- * Fair queue using {@link PacketPassInterface}.
- */
-typedef struct PacketPassFairQueue_s {
-    PacketPassInterface *output;
-    BPendingGroup *pg;
-    int use_cancel;
-    int packet_weight;
-    struct PacketPassFairQueueFlow_s *sending_flow;
-    int sending_len;
-    struct PacketPassFairQueueFlow_s *previous_flow;
-    PacketPassFairQueue__Tree queued_tree;
-    LinkedList1 flows_list;
-    int freeing;
-    BPending schedule_job;
-    DebugObject d_obj;
-    DebugCounter d_ctr;
-} PacketPassFairQueue;
-
-/**
- * Initializes the queue.
- *
- * @param m the object
- * @param output output interface
- * @param pg pending group
- * @param use_cancel whether cancel functionality is required. Must be 0 or 1.
- *                   If 1, output must support cancel functionality.
- * @param packet_weight additional weight a packet bears. Must be >0, to keep
- *                      the queue fair for zero size packets.
- * @return 1 on success, 0 on failure (because output MTU is too large)
- */
-int PacketPassFairQueue_Init (PacketPassFairQueue *m, PacketPassInterface *output, BPendingGroup *pg, int use_cancel, int packet_weight) WARN_UNUSED;
-
-/**
- * Frees the queue.
- * All flows must have been freed.
- *
- * @param m the object
- */
-void PacketPassFairQueue_Free (PacketPassFairQueue *m);
-
-/**
- * Prepares for freeing the entire queue. Must be called to allow freeing
- * the flows in the process of freeing the entire queue.
- * After this function is called, flows and the queue must be freed
- * before any further I/O.
- * May be called multiple times.
- * The queue enters freeing state.
- *
- * @param m the object
- */
-void PacketPassFairQueue_PrepareFree (PacketPassFairQueue *m);
-
-/**
- * Returns the MTU of the queue.
- *
- * @param m the object
- */
-int PacketPassFairQueue_GetMTU (PacketPassFairQueue *m);
-
-/**
- * Initializes a queue flow.
- * Queue must not be in freeing state.
- * Must not be called from queue calls to output.
- *
- * @param flow the object
- * @param m queue to attach to
- */
-void PacketPassFairQueueFlow_Init (PacketPassFairQueueFlow *flow, PacketPassFairQueue *m);
-
-/**
- * Frees a queue flow.
- * Unless the queue is in freeing state:
- * - The flow must not be busy as indicated by {@link PacketPassFairQueueFlow_IsBusy}.
- * - Must not be called from queue calls to output.
- *
- * @param flow the object
- */
-void PacketPassFairQueueFlow_Free (PacketPassFairQueueFlow *flow);
-
-/**
- * Does nothing.
- * It must be possible to free the flow (see {@link PacketPassFairQueueFlow_Free}).
- * 
- * @param flow the object
- */
-void PacketPassFairQueueFlow_AssertFree (PacketPassFairQueueFlow *flow);
-
-/**
- * Determines if the flow is busy. If the flow is considered busy, it must not
- * be freed. At any given time, at most one flow will be indicated as busy.
- * Queue must not be in freeing state.
- * Must not be called from queue calls to output.
- *
- * @param flow the object
- * @return 0 if not busy, 1 is busy
- */
-int PacketPassFairQueueFlow_IsBusy (PacketPassFairQueueFlow *flow);
-
-/**
- * Requests the output to stop processing the current packet as soon as possible.
- * Cancel functionality must be enabled for the queue.
- * The flow must be busy as indicated by {@link PacketPassFairQueueFlow_IsBusy}.
- * Queue must not be in freeing state.
- * 
- * @param flow the object
- */
-void PacketPassFairQueueFlow_RequestCancel (PacketPassFairQueueFlow *flow);
-
-/**
- * Sets up a callback to be called when the flow is no longer busy.
- * The handler will be called as soon as the flow is no longer busy, i.e. it is not
- * possible that this flow is no longer busy before the handler is called.
- * The flow must be busy as indicated by {@link PacketPassFairQueueFlow_IsBusy}.
- * Queue must not be in freeing state.
- * Must not be called from queue calls to output.
- *
- * @param flow the object
- * @param handler callback function. NULL to disable.
- * @param user value passed to callback function. Ignored if handler is NULL.
- */
-void PacketPassFairQueueFlow_SetBusyHandler (PacketPassFairQueueFlow *flow, PacketPassFairQueue_handler_busy handler, void *user);
-
-/**
- * Returns the input interface of the flow.
- *
- * @param flow the object
- * @return input interface
- */
-PacketPassInterface * PacketPassFairQueueFlow_GetInput (PacketPassFairQueueFlow *flow);
-
-#endif
diff --git a/external/badvpn_dns/flow/PacketPassFairQueue_tree.h b/external/badvpn_dns/flow/PacketPassFairQueue_tree.h
deleted file mode 100644
index 5dd0a7d..0000000
--- a/external/badvpn_dns/flow/PacketPassFairQueue_tree.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#define SAVL_PARAM_NAME PacketPassFairQueue__Tree
-#define SAVL_PARAM_FEATURE_COUNTS 0
-#define SAVL_PARAM_FEATURE_NOKEYS 1
-#define SAVL_PARAM_TYPE_ENTRY struct PacketPassFairQueueFlow_s
-#define SAVL_PARAM_TYPE_ARG int
-#define SAVL_PARAM_FUN_COMPARE_ENTRIES(arg, entry1, entry2) compare_flows((entry1), (entry2))
-#define SAVL_PARAM_MEMBER_NODE queued.tree_node
diff --git a/external/badvpn_dns/flow/PacketPassFifoQueue.c b/external/badvpn_dns/flow/PacketPassFifoQueue.c
deleted file mode 100644
index 0395006..0000000
--- a/external/badvpn_dns/flow/PacketPassFifoQueue.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/**
- * @file PacketPassFifoQueue.c
- * @author Ambroz Bizjak <ambrop7 at gmail.com>
- * 
- * @section LICENSE
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of co