From 4a1f21163c041e673604813a8c48c14bf9f20222 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 25 Jun 2018 19:52:15 +0200 Subject: move dns ops again, 2nd try --- configure.ac | 1 - po/POTFILES.in | 132 ++--- src/Makefile.am | 1 - src/dns/Makefile.am | 34 -- src/dns/dnsparser.c | 1334 ------------------------------------------------- src/dns/dnsstub.c | 749 --------------------------- src/tun/regex.c | 834 ------------------------------- src/tun/test_regex.c | 179 ------- src/tun/test_tun.c | 72 --- src/tun/tun.c | 309 ------------ src/util/Makefile.am | 25 +- src/util/dnsparser.c | 1334 +++++++++++++++++++++++++++++++++++++++++++++++++ src/util/dnsstub.c | 749 +++++++++++++++++++++++++++ src/util/regex.c | 834 +++++++++++++++++++++++++++++++ src/util/test_regex.c | 179 +++++++ src/util/test_tun.c | 72 +++ src/util/tun.c | 309 ++++++++++++ 17 files changed, 3566 insertions(+), 3581 deletions(-) delete mode 100644 src/dns/dnsparser.c delete mode 100644 src/dns/dnsstub.c delete mode 100644 src/tun/regex.c delete mode 100644 src/tun/test_regex.c delete mode 100644 src/tun/test_tun.c delete mode 100644 src/tun/tun.c create mode 100644 src/util/dnsparser.c create mode 100644 src/util/dnsstub.c create mode 100644 src/util/regex.c create mode 100644 src/util/test_regex.c create mode 100644 src/util/test_tun.c create mode 100644 src/util/tun.c diff --git a/configure.ac b/configure.ac index c8e316416..3d68ee9b0 100644 --- a/configure.ac +++ b/configure.ac @@ -1722,7 +1722,6 @@ src/testing/Makefile src/topology/Makefile src/transport/Makefile src/transport/transport.conf -src/tun/Makefile src/util/Makefile src/util/resolver.conf src/vpn/Makefile diff --git a/po/POTFILES.in b/po/POTFILES.in index de6bd90e4..38fa52508 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -4,21 +4,13 @@ src/arm/arm_monitor_api.c src/arm/gnunet-arm.c src/arm/gnunet-service-arm.c src/arm/mockup-service.c -src/ats-tests/ats-testing-experiment.c -src/ats-tests/ats-testing-log.c -src/ats-tests/ats-testing-preferences.c -src/ats-tests/ats-testing-traffic.c -src/ats-tests/ats-testing.c -src/ats-tests/gnunet-ats-sim.c -src/ats-tests/gnunet-solver-eval.c -src/ats-tool/gnunet-ats.c src/ats/ats_api_connectivity.c src/ats/ats_api_performance.c src/ats/ats_api_scanner.c src/ats/ats_api_scheduling.c src/ats/gnunet-ats-solver-eval.c -src/ats/gnunet-service-ats.c src/ats/gnunet-service-ats_addresses.c +src/ats/gnunet-service-ats.c src/ats/gnunet-service-ats_connectivity.c src/ats/gnunet-service-ats_normalization.c src/ats/gnunet-service-ats_performance.c @@ -29,6 +21,14 @@ src/ats/gnunet-service-ats_scheduling.c src/ats/plugin_ats_mlp.c src/ats/plugin_ats_proportional.c src/ats/plugin_ats_ril.c +src/ats-tests/ats-testing.c +src/ats-tests/ats-testing-experiment.c +src/ats-tests/ats-testing-log.c +src/ats-tests/ats-testing-preferences.c +src/ats-tests/ats-testing-traffic.c +src/ats-tests/gnunet-ats-sim.c +src/ats-tests/gnunet-solver-eval.c +src/ats-tool/gnunet-ats.c src/auction/gnunet-auction-create.c src/auction/gnunet-auction-info.c src/auction/gnunet-auction-join.c @@ -40,8 +40,8 @@ src/block/plugin_block_test.c src/cadet/cadet_api.c src/cadet/cadet_test_lib.c src/cadet/desirability_table.c -src/cadet/gnunet-cadet-profiler.c src/cadet/gnunet-cadet.c +src/cadet/gnunet-cadet-profiler.c src/cadet/gnunet-service-cadet.c src/cadet/gnunet-service-cadet_channel.c src/cadet/gnunet-service-cadet_connection.c @@ -57,15 +57,15 @@ src/consensus/gnunet-service-consensus.c src/consensus/plugin_block_consensus.c src/conversation/conversation_api.c src/conversation/conversation_api_call.c -src/conversation/gnunet-conversation-test.c src/conversation/gnunet-conversation.c -src/conversation/gnunet-helper-audio-playback-gst.c +src/conversation/gnunet-conversation-test.c +src/conversation/gnunet_gst.c +src/conversation/gnunet_gst_test.c src/conversation/gnunet-helper-audio-playback.c -src/conversation/gnunet-helper-audio-record-gst.c +src/conversation/gnunet-helper-audio-playback-gst.c src/conversation/gnunet-helper-audio-record.c +src/conversation/gnunet-helper-audio-record-gst.c src/conversation/gnunet-service-conversation.c -src/conversation/gnunet_gst.c -src/conversation/gnunet_gst_test.c src/conversation/microphone.c src/conversation/plugin_gnsrecord_conversation.c src/conversation/speaker.c @@ -102,6 +102,7 @@ src/dht/dht_api.c src/dht/dht_test_lib.c src/dht/gnunet-dht-get.c src/dht/gnunet-dht-monitor.c +src/dht/gnunet_dht_profiler.c src/dht/gnunet-dht-put.c src/dht/gnunet-service-dht.c src/dht/gnunet-service-dht_clients.c @@ -110,11 +111,8 @@ src/dht/gnunet-service-dht_hello.c src/dht/gnunet-service-dht_neighbours.c src/dht/gnunet-service-dht_nse.c src/dht/gnunet-service-dht_routing.c -src/dht/gnunet_dht_profiler.c src/dht/plugin_block_dht.c src/dns/dns_api.c -src/dns/dnsparser.c -src/dns/dnsstub.c src/dns/gnunet-dns-monitor.c src/dns/gnunet-dns-redirector.c src/dns/gnunet-helper-dns.c @@ -126,8 +124,8 @@ src/dv/gnunet-dv.c src/dv/gnunet-service-dv.c src/dv/plugin_transport_dv.c src/exit/gnunet-daemon-exit.c -src/exit/gnunet-helper-exit-windows.c src/exit/gnunet-helper-exit.c +src/exit/gnunet-helper-exit-windows.c src/fragmentation/defragmentation.c src/fragmentation/fragmentation.c src/fs/fs_api.c @@ -152,8 +150,8 @@ src/fs/gnunet-auto-share.c src/fs/gnunet-daemon-fsprofiler.c src/fs/gnunet-directory.c src/fs/gnunet-download.c -src/fs/gnunet-fs-profiler.c src/fs/gnunet-fs.c +src/fs/gnunet-fs-profiler.c src/fs/gnunet-helper-fs-publish.c src/fs/gnunet-publish.c src/fs/gnunet-search.c @@ -173,10 +171,10 @@ src/gns/gns_tld_api.c src/gns/gnunet-bcd.c src/gns/gnunet-dns2gns.c src/gns/gnunet-gns-benchmark.c +src/gns/gnunet-gns.c src/gns/gnunet-gns-helper-service-w32.c src/gns/gnunet-gns-import.c src/gns/gnunet-gns-proxy.c -src/gns/gnunet-gns.c src/gns/gnunet-service-gns.c src/gns/gnunet-service-gns_interceptor.c src/gns/gnunet-service-gns_resolver.c @@ -185,15 +183,15 @@ src/gns/nss/nss_gns_query.c src/gns/plugin_block_gns.c src/gns/plugin_gnsrecord_gns.c src/gns/plugin_rest_gns.c -src/gns/w32nsp-install.c -src/gns/w32nsp-resolve.c -src/gns/w32nsp-uninstall.c -src/gns/w32nsp.c src/gnsrecord/gnsrecord.c src/gnsrecord/gnsrecord_crypto.c src/gnsrecord/gnsrecord_misc.c src/gnsrecord/gnsrecord_serialization.c src/gnsrecord/plugin_gnsrecord_dns.c +src/gns/w32nsp.c +src/gns/w32nsp-install.c +src/gns/w32nsp-resolve.c +src/gns/w32nsp-uninstall.c src/hello/address.c src/hello/gnunet-hello.c src/hello/hello.c @@ -202,6 +200,11 @@ src/hostlist/gnunet-daemon-hostlist_client.c src/hostlist/gnunet-daemon-hostlist_server.c src/identity-attribute/identity_attribute.c src/identity-attribute/plugin_identity_attribute_gnuid.c +src/identity/gnunet-identity.c +src/identity/gnunet-service-identity.c +src/identity/identity_api.c +src/identity/identity_api_lookup.c +src/identity/plugin_rest_identity.c src/identity-provider/gnunet-idp.c src/identity-provider/gnunet-service-identity-provider.c src/identity-provider/identity_provider_api.c @@ -210,20 +213,15 @@ src/identity-provider/plugin_gnsrecord_identity_provider.c src/identity-provider/plugin_identity_provider_sqlite.c src/identity-provider/plugin_rest_identity_provider.c src/identity-provider/plugin_rest_openid_connect.c -src/identity/gnunet-identity.c -src/identity/gnunet-service-identity.c -src/identity/identity_api.c -src/identity/identity_api_lookup.c -src/identity/plugin_rest_identity.c -src/json/json.c -src/json/json_generator.c -src/json/json_helper.c -src/json/json_mhd.c src/jsonapi/jsonapi.c src/jsonapi/jsonapi_document.c src/jsonapi/jsonapi_error.c src/jsonapi/jsonapi_relationship.c src/jsonapi/jsonapi_resource.c +src/json/json.c +src/json/json_generator.c +src/json/json_helper.c +src/json/json_mhd.c src/multicast/gnunet-multicast.c src/multicast/gnunet-service-multicast.c src/multicast/multicast_api.c @@ -237,8 +235,8 @@ src/namecache/namecache_api.c src/namecache/plugin_namecache_flat.c src/namecache/plugin_namecache_postgres.c src/namecache/plugin_namecache_sqlite.c -src/namestore/gnunet-namestore-fcfsd.c src/namestore/gnunet-namestore.c +src/namestore/gnunet-namestore-fcfsd.c src/namestore/gnunet-service-namestore.c src/namestore/gnunet-zoneimport.c src/namestore/namestore_api.c @@ -254,10 +252,10 @@ src/nat-auto/gnunet-service-nat-auto.c src/nat-auto/gnunet-service-nat-auto_legacy.c src/nat-auto/nat_auto_api.c src/nat-auto/nat_auto_api_test.c -src/nat/gnunet-helper-nat-client-windows.c src/nat/gnunet-helper-nat-client.c -src/nat/gnunet-helper-nat-server-windows.c +src/nat/gnunet-helper-nat-client-windows.c src/nat/gnunet-helper-nat-server.c +src/nat/gnunet-helper-nat-server-windows.c src/nat/gnunet-nat.c src/nat/gnunet-service-nat.c src/nat/gnunet-service-nat_externalip.c @@ -266,15 +264,15 @@ src/nat/gnunet-service-nat_mini.c src/nat/gnunet-service-nat_stun.c src/nat/nat_api.c src/nat/nat_api_stun.c -src/nse/gnunet-nse-profiler.c src/nse/gnunet-nse.c +src/nse/gnunet-nse-profiler.c src/nse/gnunet-service-nse.c src/nse/nse_api.c -src/peerinfo-tool/gnunet-peerinfo.c -src/peerinfo-tool/gnunet-peerinfo_plugins.c src/peerinfo/gnunet-service-peerinfo.c src/peerinfo/peerinfo_api.c src/peerinfo/peerinfo_api_notify.c +src/peerinfo-tool/gnunet-peerinfo.c +src/peerinfo-tool/gnunet-peerinfo_plugins.c src/peerstore/gnunet-peerstore.c src/peerstore/gnunet-service-peerstore.c src/peerstore/peerstore_api.c @@ -319,20 +317,20 @@ src/revocation/gnunet-revocation.c src/revocation/gnunet-service-revocation.c src/revocation/plugin_block_revocation.c src/revocation/revocation_api.c -src/rps/gnunet-rps-profiler.c src/rps/gnunet-rps.c +src/rps/gnunet-rps-profiler.c src/rps/gnunet-service-rps.c src/rps/gnunet-service-rps_custommap.c src/rps/gnunet-service-rps_sampler.c src/rps/gnunet-service-rps_sampler_elem.c src/rps/gnunet-service-rps_view.c -src/rps/rps-test_util.c src/rps/rps_api.c +src/rps/rps-test_util.c src/scalarproduct/gnunet-scalarproduct.c -src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c -src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c src/scalarproduct/gnunet-service-scalarproduct_alice.c src/scalarproduct/gnunet-service-scalarproduct_bob.c +src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c +src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c src/scalarproduct/scalarproduct_api.c src/secretsharing/gnunet-secretsharing-profiler.c src/secretsharing/gnunet-service-secretsharing.c @@ -361,16 +359,15 @@ src/statistics/gnunet-statistics.c src/statistics/statistics_api.c src/template/gnunet-service-template.c src/template/gnunet-template.c -src/testbed-logger/gnunet-service-testbed-logger.c -src/testbed-logger/testbed_logger_api.c src/testbed/generate-underlay-topology.c src/testbed/gnunet-daemon-latency-logger.c src/testbed/gnunet-daemon-testbed-blacklist.c src/testbed/gnunet-daemon-testbed-underlay.c src/testbed/gnunet-helper-testbed.c +src/testbed/gnunet_mpi_test.c src/testbed/gnunet-service-test-barriers.c -src/testbed/gnunet-service-testbed.c src/testbed/gnunet-service-testbed_barriers.c +src/testbed/gnunet-service-testbed.c src/testbed/gnunet-service-testbed_cache.c src/testbed/gnunet-service-testbed_connectionpool.c src/testbed/gnunet-service-testbed_cpustatus.c @@ -378,19 +375,20 @@ src/testbed/gnunet-service-testbed_links.c src/testbed/gnunet-service-testbed_meminfo.c src/testbed/gnunet-service-testbed_oc.c src/testbed/gnunet-service-testbed_peers.c -src/testbed/gnunet-testbed-profiler.c -src/testbed/gnunet_mpi_test.c src/testbed/gnunet_testbed_mpi_spawn.c -src/testbed/testbed_api.c +src/testbed/gnunet-testbed-profiler.c +src/testbed-logger/gnunet-service-testbed-logger.c +src/testbed-logger/testbed_logger_api.c src/testbed/testbed_api_barriers.c +src/testbed/testbed_api.c src/testbed/testbed_api_hosts.c src/testbed/testbed_api_operations.c src/testbed/testbed_api_peers.c src/testbed/testbed_api_sd.c src/testbed/testbed_api_services.c src/testbed/testbed_api_statistics.c -src/testbed/testbed_api_test.c src/testbed/testbed_api_testbed.c +src/testbed/testbed_api_test.c src/testbed/testbed_api_topology.c src/testbed/testbed_api_underlay.c src/testing/gnunet-testing.c @@ -399,28 +397,28 @@ src/testing/testing.c src/topology/friends.c src/topology/gnunet-daemon-topology.c src/transport/gnunet-helper-transport-bluetooth.c -src/transport/gnunet-helper-transport-wlan-dummy.c src/transport/gnunet-helper-transport-wlan.c -src/transport/gnunet-service-transport.c +src/transport/gnunet-helper-transport-wlan-dummy.c src/transport/gnunet-service-transport_ats.c +src/transport/gnunet-service-transport.c src/transport/gnunet-service-transport_hello.c src/transport/gnunet-service-transport_manipulation.c src/transport/gnunet-service-transport_neighbours.c src/transport/gnunet-service-transport_plugins.c src/transport/gnunet-service-transport_validation.c +src/transport/gnunet-transport.c src/transport/gnunet-transport-certificate-creation.c src/transport/gnunet-transport-profiler.c src/transport/gnunet-transport-wlan-receiver.c src/transport/gnunet-transport-wlan-sender.c -src/transport/gnunet-transport.c src/transport/plugin_transport_http_client.c src/transport/plugin_transport_http_common.c src/transport/plugin_transport_http_server.c src/transport/plugin_transport_smtp.c src/transport/plugin_transport_tcp.c src/transport/plugin_transport_template.c -src/transport/plugin_transport_udp.c src/transport/plugin_transport_udp_broadcasting.c +src/transport/plugin_transport_udp.c src/transport/plugin_transport_unix.c src/transport/plugin_transport_wlan.c src/transport/plugin_transport_xt.c @@ -429,11 +427,6 @@ src/transport/tcp_connection_legacy.c src/transport/tcp_server_legacy.c src/transport/tcp_server_mst_legacy.c src/transport/tcp_service_legacy.c -src/transport/transport-testing-filenames.c -src/transport/transport-testing-loggers.c -src/transport/transport-testing-main.c -src/transport/transport-testing-send.c -src/transport/transport-testing.c src/transport/transport_api_address_to_string.c src/transport/transport_api_blacklist.c src/transport/transport_api_core.c @@ -442,8 +435,11 @@ src/transport/transport_api_manipulation.c src/transport/transport_api_monitor_peers.c src/transport/transport_api_monitor_plugins.c src/transport/transport_api_offer_hello.c -src/tun/regex.c -src/tun/tun.c +src/transport/transport-testing.c +src/transport/transport-testing-filenames.c +src/transport/transport-testing-loggers.c +src/transport/transport-testing-main.c +src/transport/transport-testing-send.c src/util/bandwidth.c src/util/bio.c src/util/client.c @@ -455,8 +451,8 @@ src/util/configuration_loader.c src/util/container_bloomfilter.c src/util/container_heap.c src/util/container_meta_data.c -src/util/container_multihashmap.c src/util/container_multihashmap32.c +src/util/container_multihashmap.c src/util/container_multipeermap.c src/util/container_multishortmap.c src/util/crypto_abe.c @@ -474,10 +470,12 @@ src/util/crypto_random.c src/util/crypto_rsa.c src/util/crypto_symmetric.c src/util/disk.c +src/util/dnsparser.c +src/util/dnsstub.c src/util/getopt.c src/util/getopt_helpers.c -src/util/gnunet-config-diff.c src/util/gnunet-config.c +src/util/gnunet-config-diff.c src/util/gnunet-ecc.c src/util/gnunet-helper-w32-console.c src/util/gnunet-resolver.c @@ -497,6 +495,7 @@ src/util/os_priority.c src/util/peer.c src/util/plugin.c src/util/program.c +src/util/regex.c src/util/resolver_api.c src/util/scheduler.c src/util/service.c @@ -505,16 +504,17 @@ src/util/socks.c src/util/speedup.c src/util/strings.c src/util/time.c +src/util/tun.c src/util/w32cat.c src/util/win.c src/util/winproc.c -src/vpn/gnunet-helper-vpn-windows.c src/vpn/gnunet-helper-vpn.c +src/vpn/gnunet-helper-vpn-windows.c src/vpn/gnunet-service-vpn.c src/vpn/gnunet-vpn.c src/vpn/vpn_api.c -src/zonemaster/gnunet-service-zonemaster-monitor.c src/zonemaster/gnunet-service-zonemaster.c +src/zonemaster/gnunet-service-zonemaster-monitor.c src/fs/fs_api.h src/include/gnunet_common.h src/include/gnunet_mq_lib.h diff --git a/src/Makefile.am b/src/Makefile.am index d8d548706..00f30adc3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -83,7 +83,6 @@ SUBDIRS = \ $(REST_DIR) \ $(JSONAPI_DIR) \ hello \ - tun \ block \ statistics \ arm \ diff --git a/src/dns/Makefile.am b/src/dns/Makefile.am index 9a4ecdcfd..ca2685765 100644 --- a/src/dns/Makefile.am +++ b/src/dns/Makefile.am @@ -27,8 +27,6 @@ install-exec-hook: endif lib_LTLIBRARIES = \ - libgnunetdnsparser.la \ - libgnunetdnsstub.la \ libgnunetdns.la libexec_PROGRAMS = \ @@ -47,9 +45,6 @@ check_SCRIPTS = \ test_gnunet_dns.sh endif -check_PROGRAMS = \ - test_hexcoder - gnunet_helper_dns_SOURCES = \ gnunet-helper-dns.c @@ -57,7 +52,6 @@ gnunet_helper_dns_SOURCES = \ gnunet_dns_monitor_SOURCES = \ gnunet-dns-monitor.c gnunet_dns_monitor_LDADD = \ - libgnunetdnsparser.la \ libgnunetdns.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) @@ -65,15 +59,12 @@ gnunet_dns_monitor_LDADD = \ gnunet_zonewalk_SOURCES = \ gnunet-zonewalk.c gnunet_zonewalk_LDADD = \ - libgnunetdnsparser.la \ - libgnunetdnsstub.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) gnunet_dns_redirector_SOURCES = \ gnunet-dns-redirector.c gnunet_dns_redirector_LDADD = \ - libgnunetdnsparser.la \ libgnunetdns.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) @@ -81,30 +72,10 @@ gnunet_dns_redirector_LDADD = \ gnunet_service_dns_SOURCES = \ gnunet-service-dns.c gnunet_service_dns_LDADD = \ - libgnunetdnsstub.la \ - $(top_builddir)/src/tun/libgnunettun.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) -libgnunetdnsparser_la_SOURCES = \ - dnsparser.c -libgnunetdnsparser_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIB) \ - -lidn -libgnunetdnsparser_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) \ - -version-info 1:0:1 - -libgnunetdnsstub_la_SOURCES = \ - dnsstub.c -libgnunetdnsstub_la_LIBADD = \ - $(top_builddir)/src/tun/libgnunettun.la \ - $(top_builddir)/src/util/libgnunetutil.la $(XLIB) -libgnunetdnsstub_la_LDFLAGS = \ - $(GN_LIB_LDFLAGS) \ - -version-info 0:0:0 - libgnunetdns_la_SOURCES = \ dns_api.c dns.h libgnunetdns_la_LIBADD = \ @@ -131,8 +102,3 @@ EXTRA_DIST = \ $(check_SCRIPTS) -test_hexcoder_SOURCES = \ - test_hexcoder.c -test_hexcoder_LDADD = \ - libgnunetdnsparser.la \ - $(top_builddir)/src/util/libgnunetutil.la diff --git a/src/dns/dnsparser.c b/src/dns/dnsparser.c deleted file mode 100644 index 32ad7c0c2..000000000 --- a/src/dns/dnsparser.c +++ /dev/null @@ -1,1334 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2010-2014 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - */ - -/** - * @file dns/dnsparser.c - * @brief helper library to parse DNS packets. - * @author Philipp Toelke - * @author Christian Grothoff - */ -#include "platform.h" -#include -#if WINDOWS -#include -#endif -#include "gnunet_util_lib.h" -#include "gnunet_dnsparser_lib.h" -#include "gnunet_tun_lib.h" - - -/** - * Check if a label in UTF-8 format can be coded into valid IDNA. - * This can fail if the ASCII-conversion becomes longer than 63 characters. - * - * @param label label to check (UTF-8 string) - * @return #GNUNET_OK if the label can be converted to IDNA, - * #GNUNET_SYSERR if the label is not valid for DNS names - */ -int -GNUNET_DNSPARSER_check_label (const char *label) -{ - char *output; - size_t slen; - - if (NULL != strchr (label, '.')) - return GNUNET_SYSERR; /* not a label! Did you mean GNUNET_DNSPARSER_check_name? */ - if (IDNA_SUCCESS != - idna_to_ascii_8z (label, &output, IDNA_ALLOW_UNASSIGNED)) - return GNUNET_SYSERR; - slen = strlen (output); -#if WINDOWS - idn_free (output); -#else - free (output); -#endif - return (slen > 63) ? GNUNET_SYSERR : GNUNET_OK; -} - - -/** - * Check if a label in UTF-8 format can be coded into valid IDNA. - * This can fail if the ASCII-conversion becomes longer than 253 characters. - * - * @param name name to check (UTF-8 string) - * @return #GNUNET_OK if the label can be converted to IDNA, - * #GNUNET_SYSERR if the label is not valid for DNS names - */ -int -GNUNET_DNSPARSER_check_name (const char *name) -{ - char *ldup; - char *output; - size_t slen; - char *tok; - - ldup = GNUNET_strdup (name); - for (tok = strtok (ldup, "."); NULL != tok; tok = strtok (NULL, ".")) - if (GNUNET_OK != - GNUNET_DNSPARSER_check_label (tok)) - { - GNUNET_free (ldup); - return GNUNET_SYSERR; - } - GNUNET_free (ldup); - if (IDNA_SUCCESS != - idna_to_ascii_8z (name, &output, IDNA_ALLOW_UNASSIGNED)) - return GNUNET_SYSERR; - slen = strlen (output); -#if WINDOWS - idn_free (output); -#else - free (output); -#endif - return (slen > 253) ? GNUNET_SYSERR : GNUNET_OK; -} - - -/** - * Free SOA information record. - * - * @param soa record to free - */ -void -GNUNET_DNSPARSER_free_soa (struct GNUNET_DNSPARSER_SoaRecord *soa) -{ - if (NULL == soa) - return; - GNUNET_free_non_null (soa->mname); - GNUNET_free_non_null (soa->rname); - GNUNET_free (soa); -} - - -/** - * Free CERT information record. - * - * @param cert record to free - */ -void -GNUNET_DNSPARSER_free_cert (struct GNUNET_DNSPARSER_CertRecord *cert) -{ - if (NULL == cert) - return; - GNUNET_free_non_null (cert->certificate_data); - GNUNET_free (cert); -} - - -/** - * Free SRV information record. - * - * @param srv record to free - */ -void -GNUNET_DNSPARSER_free_srv (struct GNUNET_DNSPARSER_SrvRecord *srv) -{ - if (NULL == srv) - return; - GNUNET_free_non_null (srv->target); - GNUNET_free (srv); -} - - -/** - * Free MX information record. - * - * @param mx record to free - */ -void -GNUNET_DNSPARSER_free_mx (struct GNUNET_DNSPARSER_MxRecord *mx) -{ - if (NULL == mx) - return; - GNUNET_free_non_null (mx->mxhost); - GNUNET_free (mx); -} - - -/** - * Free the given DNS record. - * - * @param r record to free - */ -void -GNUNET_DNSPARSER_free_record (struct GNUNET_DNSPARSER_Record *r) -{ - GNUNET_free_non_null (r->name); - switch (r->type) - { - case GNUNET_DNSPARSER_TYPE_MX: - GNUNET_DNSPARSER_free_mx (r->data.mx); - break; - case GNUNET_DNSPARSER_TYPE_SOA: - GNUNET_DNSPARSER_free_soa (r->data.soa); - break; - case GNUNET_DNSPARSER_TYPE_SRV: - GNUNET_DNSPARSER_free_srv (r->data.srv); - break; - case GNUNET_DNSPARSER_TYPE_CERT: - GNUNET_DNSPARSER_free_cert (r->data.cert); - break; - case GNUNET_DNSPARSER_TYPE_NS: - case GNUNET_DNSPARSER_TYPE_CNAME: - case GNUNET_DNSPARSER_TYPE_PTR: - GNUNET_free_non_null (r->data.hostname); - break; - default: - GNUNET_free_non_null (r->data.raw.data); - break; - } -} - - -/** - * Parse name inside of a DNS query or record. - * - * @param udp_payload entire UDP payload - * @param udp_payload_length length of @a udp_payload - * @param off pointer to the offset of the name to parse in the udp_payload (to be - * incremented by the size of the name) - * @param depth current depth of our recursion (to prevent stack overflow) - * @return name as 0-terminated C string on success, NULL if the payload is malformed - */ -static char * -parse_name (const char *udp_payload, - size_t udp_payload_length, - size_t *off, - unsigned int depth) -{ - const uint8_t *input = (const uint8_t *) udp_payload; - char *ret; - char *tmp; - char *xstr; - uint8_t len; - size_t xoff; - char *utf8; - Idna_rc rc; - - ret = GNUNET_strdup (""); - while (1) - { - if (*off >= udp_payload_length) - { - GNUNET_break_op (0); - goto error; - } - len = input[*off]; - if (0 == len) - { - (*off)++; - break; - } - if (len < 64) - { - if (*off + 1 + len > udp_payload_length) - { - GNUNET_break_op (0); - goto error; - } - GNUNET_asprintf (&tmp, - "%.*s", - (int) len, - &udp_payload[*off + 1]); - if (IDNA_SUCCESS != - (rc = idna_to_unicode_8z8z (tmp, &utf8, IDNA_ALLOW_UNASSIGNED))) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Failed to convert DNS IDNA name `%s' to UTF-8: %s\n"), - tmp, - idna_strerror (rc)); - GNUNET_free (tmp); - GNUNET_asprintf (&tmp, - "%s%.*s.", - ret, - (int) len, - &udp_payload[*off + 1]); - } - else - { - GNUNET_free (tmp); - GNUNET_asprintf (&tmp, - "%s%s.", - ret, - utf8); -#if WINDOWS - idn_free (utf8); -#else - free (utf8); -#endif - } - GNUNET_free (ret); - ret = tmp; - *off += 1 + len; - } - else if ((64 | 128) == (len & (64 | 128)) ) - { - if (depth > 32) - { - GNUNET_break_op (0); - goto error; /* hard bound on stack to prevent "infinite" recursion, disallow! */ - } - /* pointer to string */ - if (*off + 1 > udp_payload_length) - { - GNUNET_break_op (0); - goto error; - } - xoff = ((len - (64 | 128)) << 8) + input[*off+1]; - xstr = parse_name (udp_payload, - udp_payload_length, - &xoff, - depth + 1); - if (NULL == xstr) - { - GNUNET_break_op (0); - goto error; - } - GNUNET_asprintf (&tmp, - "%s%s.", - ret, - xstr); - GNUNET_free (ret); - GNUNET_free (xstr); - ret = tmp; - if (strlen (ret) > udp_payload_length) - { - GNUNET_break_op (0); - goto error; /* we are looping (building an infinite string) */ - } - *off += 2; - /* pointers always terminate names */ - break; - } - else - { - /* neither pointer nor inline string, not supported... */ - GNUNET_break_op (0); - goto error; - } - } - if (0 < strlen(ret)) - ret[strlen(ret)-1] = '\0'; /* eat tailing '.' */ - return ret; - error: - GNUNET_break_op (0); - GNUNET_free (ret); - return NULL; -} - - -/** - * Parse name inside of a DNS query or record. - * - * @param udp_payload entire UDP payload - * @param udp_payload_length length of @a udp_payload - * @param off pointer to the offset of the name to parse in the udp_payload (to be - * incremented by the size of the name) - * @return name as 0-terminated C string on success, NULL if the payload is malformed - */ -char * -GNUNET_DNSPARSER_parse_name (const char *udp_payload, - size_t udp_payload_length, - size_t *off) -{ - return parse_name (udp_payload, udp_payload_length, off, 0); -} - - -/** - * Parse a DNS query entry. - * - * @param udp_payload entire UDP payload - * @param udp_payload_length length of @a udp_payload - * @param off pointer to the offset of the query to parse in the udp_payload (to be - * incremented by the size of the query) - * @param q where to write the query information - * @return #GNUNET_OK on success, #GNUNET_SYSERR if the query is malformed - */ -int -GNUNET_DNSPARSER_parse_query (const char *udp_payload, - size_t udp_payload_length, - size_t *off, - struct GNUNET_DNSPARSER_Query *q) -{ - char *name; - struct GNUNET_TUN_DnsQueryLine ql; - - name = GNUNET_DNSPARSER_parse_name (udp_payload, - udp_payload_length, - off); - if (NULL == name) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - q->name = name; - if (*off + sizeof (struct GNUNET_TUN_DnsQueryLine) > udp_payload_length) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - GNUNET_memcpy (&ql, &udp_payload[*off], sizeof (ql)); - *off += sizeof (ql); - q->type = ntohs (ql.type); - q->dns_traffic_class = ntohs (ql.dns_traffic_class); - return GNUNET_OK; -} - - -/** - * Parse a DNS SOA record. - * - * @param udp_payload reference to UDP packet - * @param udp_payload_length length of @a udp_payload - * @param off pointer to the offset of the query to parse in the SOA record (to be - * incremented by the size of the record), unchanged on error - * @return the parsed SOA record, NULL on error - */ -struct GNUNET_DNSPARSER_SoaRecord * -GNUNET_DNSPARSER_parse_soa (const char *udp_payload, - size_t udp_payload_length, - size_t *off) -{ - struct GNUNET_DNSPARSER_SoaRecord *soa; - struct GNUNET_TUN_DnsSoaRecord soa_bin; - size_t old_off; - - old_off = *off; - soa = GNUNET_new (struct GNUNET_DNSPARSER_SoaRecord); - soa->mname = GNUNET_DNSPARSER_parse_name (udp_payload, - udp_payload_length, - off); - soa->rname = GNUNET_DNSPARSER_parse_name (udp_payload, - udp_payload_length, - off); - if ( (NULL == soa->mname) || - (NULL == soa->rname) || - (*off + sizeof (struct GNUNET_TUN_DnsSoaRecord) > udp_payload_length) ) - { - GNUNET_break_op (0); - GNUNET_DNSPARSER_free_soa (soa); - *off = old_off; - return NULL; - } - GNUNET_memcpy (&soa_bin, - &udp_payload[*off], - sizeof (struct GNUNET_TUN_DnsSoaRecord)); - soa->serial = ntohl (soa_bin.serial); - soa->refresh = ntohl (soa_bin.refresh); - soa->retry = ntohl (soa_bin.retry); - soa->expire = ntohl (soa_bin.expire); - soa->minimum_ttl = ntohl (soa_bin.minimum); - (*off) += sizeof (struct GNUNET_TUN_DnsSoaRecord); - return soa; -} - - -/** - * Parse a DNS MX record. - * - * @param udp_payload reference to UDP packet - * @param udp_payload_length length of @a udp_payload - * @param off pointer to the offset of the query to parse in the MX record (to be - * incremented by the size of the record), unchanged on error - * @return the parsed MX record, NULL on error - */ -struct GNUNET_DNSPARSER_MxRecord * -GNUNET_DNSPARSER_parse_mx (const char *udp_payload, - size_t udp_payload_length, - size_t *off) -{ - struct GNUNET_DNSPARSER_MxRecord *mx; - uint16_t mxpref; - size_t old_off; - - old_off = *off; - if (*off + sizeof (uint16_t) > udp_payload_length) - { - GNUNET_break_op (0); - return NULL; - } - GNUNET_memcpy (&mxpref, &udp_payload[*off], sizeof (uint16_t)); - (*off) += sizeof (uint16_t); - mx = GNUNET_new (struct GNUNET_DNSPARSER_MxRecord); - mx->preference = ntohs (mxpref); - mx->mxhost = GNUNET_DNSPARSER_parse_name (udp_payload, - udp_payload_length, - off); - if (NULL == mx->mxhost) - { - GNUNET_break_op (0); - GNUNET_DNSPARSER_free_mx (mx); - *off = old_off; - return NULL; - } - return mx; -} - - -/** - * Parse a DNS SRV record. - * - * @param udp_payload reference to UDP packet - * @param udp_payload_length length of @a udp_payload - * @param off pointer to the offset of the query to parse in the SRV record (to be - * incremented by the size of the record), unchanged on error - * @return the parsed SRV record, NULL on error - */ -struct GNUNET_DNSPARSER_SrvRecord * -GNUNET_DNSPARSER_parse_srv (const char *udp_payload, - size_t udp_payload_length, - size_t *off) -{ - struct GNUNET_DNSPARSER_SrvRecord *srv; - struct GNUNET_TUN_DnsSrvRecord srv_bin; - size_t old_off; - - old_off = *off; - if (*off + sizeof (struct GNUNET_TUN_DnsSrvRecord) > udp_payload_length) - return NULL; - GNUNET_memcpy (&srv_bin, - &udp_payload[*off], - sizeof (struct GNUNET_TUN_DnsSrvRecord)); - (*off) += sizeof (struct GNUNET_TUN_DnsSrvRecord); - srv = GNUNET_new (struct GNUNET_DNSPARSER_SrvRecord); - srv->priority = ntohs (srv_bin.prio); - srv->weight = ntohs (srv_bin.weight); - srv->port = ntohs (srv_bin.port); - srv->target = GNUNET_DNSPARSER_parse_name (udp_payload, - udp_payload_length, - off); - if (NULL == srv->target) - { - GNUNET_DNSPARSER_free_srv (srv); - *off = old_off; - return NULL; - } - return srv; -} - - -/** - * Parse a DNS CERT record. - * - * @param udp_payload reference to UDP packet - * @param udp_payload_length length of @a udp_payload - * @param off pointer to the offset of the query to parse in the CERT record (to be - * incremented by the size of the record), unchanged on error - * @return the parsed CERT record, NULL on error - */ -struct GNUNET_DNSPARSER_CertRecord * -GNUNET_DNSPARSER_parse_cert (const char *udp_payload, - size_t udp_payload_length, - size_t *off) -{ - struct GNUNET_DNSPARSER_CertRecord *cert; - struct GNUNET_TUN_DnsCertRecord dcert; - - if (*off + sizeof (struct GNUNET_TUN_DnsCertRecord) >= udp_payload_length) - { - GNUNET_break_op (0); - return NULL; - } - GNUNET_memcpy (&dcert, &udp_payload[*off], sizeof (struct GNUNET_TUN_DnsCertRecord)); - (*off) += sizeof (struct GNUNET_TUN_DnsCertRecord); - cert = GNUNET_new (struct GNUNET_DNSPARSER_CertRecord); - cert->cert_type = ntohs (dcert.cert_type); - cert->cert_tag = ntohs (dcert.cert_tag); - cert->algorithm = dcert.algorithm; - cert->certificate_size = udp_payload_length - (*off); - cert->certificate_data = GNUNET_malloc (cert->certificate_size); - GNUNET_memcpy (cert->certificate_data, - &udp_payload[*off], - cert->certificate_size); - (*off) += cert->certificate_size; - return cert; -} - - -/** - * Parse a DNS record entry. - * - * @param udp_payload entire UDP payload - * @param udp_payload_length length of @a udp_payload - * @param off pointer to the offset of the record to parse in the udp_payload (to be - * incremented by the size of the record) - * @param r where to write the record information - * @return #GNUNET_OK on success, #GNUNET_SYSERR if the record is malformed - */ -int -GNUNET_DNSPARSER_parse_record (const char *udp_payload, - size_t udp_payload_length, - size_t *off, - struct GNUNET_DNSPARSER_Record *r) -{ - char *name; - struct GNUNET_TUN_DnsRecordLine rl; - size_t old_off; - uint16_t data_len; - - name = GNUNET_DNSPARSER_parse_name (udp_payload, - udp_payload_length, - off); - if (NULL == name) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - r->name = name; - if (*off + sizeof (struct GNUNET_TUN_DnsRecordLine) > udp_payload_length) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - GNUNET_memcpy (&rl, &udp_payload[*off], sizeof (rl)); - (*off) += sizeof (rl); - r->type = ntohs (rl.type); - r->dns_traffic_class = ntohs (rl.dns_traffic_class); - r->expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, - ntohl (rl.ttl))); - data_len = ntohs (rl.data_len); - if (*off + data_len > udp_payload_length) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - old_off = *off; - switch (r->type) - { - case GNUNET_DNSPARSER_TYPE_NS: - case GNUNET_DNSPARSER_TYPE_CNAME: - case GNUNET_DNSPARSER_TYPE_DNAME: - case GNUNET_DNSPARSER_TYPE_PTR: - r->data.hostname = GNUNET_DNSPARSER_parse_name (udp_payload, - udp_payload_length, - off); - if ( (NULL == r->data.hostname) || - (old_off + data_len != *off) ) - return GNUNET_SYSERR; - return GNUNET_OK; - case GNUNET_DNSPARSER_TYPE_SOA: - r->data.soa = GNUNET_DNSPARSER_parse_soa (udp_payload, - udp_payload_length, - off); - if ( (NULL == r->data.soa) || - (old_off + data_len != *off) ) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; - case GNUNET_DNSPARSER_TYPE_MX: - r->data.mx = GNUNET_DNSPARSER_parse_mx (udp_payload, - udp_payload_length, - off); - if ( (NULL == r->data.mx) || - (old_off + data_len != *off) ) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; - case GNUNET_DNSPARSER_TYPE_SRV: - r->data.srv = GNUNET_DNSPARSER_parse_srv (udp_payload, - udp_payload_length, - off); - if ( (NULL == r->data.srv) || - (old_off + data_len != *off) ) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; - default: - r->data.raw.data = GNUNET_malloc (data_len); - r->data.raw.data_len = data_len; - GNUNET_memcpy (r->data.raw.data, - &udp_payload[*off], - data_len); - break; - } - (*off) += data_len; - return GNUNET_OK; -} - - -/** - * Parse a UDP payload of a DNS packet in to a nice struct for further - * processing and manipulation. - * - * @param udp_payload wire-format of the DNS packet - * @param udp_payload_length number of bytes in @a udp_payload - * @return NULL on error, otherwise the parsed packet - */ -struct GNUNET_DNSPARSER_Packet * -GNUNET_DNSPARSER_parse (const char *udp_payload, - size_t udp_payload_length) -{ - struct GNUNET_DNSPARSER_Packet *p; - const struct GNUNET_TUN_DnsHeader *dns; - size_t off; - unsigned int n; - unsigned int i; - - if (udp_payload_length < sizeof (struct GNUNET_TUN_DnsHeader)) - return NULL; - dns = (const struct GNUNET_TUN_DnsHeader *) udp_payload; - off = sizeof (struct GNUNET_TUN_DnsHeader); - p = GNUNET_new (struct GNUNET_DNSPARSER_Packet); - p->flags = dns->flags; - p->id = dns->id; - n = ntohs (dns->query_count); - if (n > 0) - { - p->queries = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Query)); - p->num_queries = n; - for (i=0;iqueries[i])) - goto error; - } - n = ntohs (dns->answer_rcount); - if (n > 0) - { - p->answers = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record)); - p->num_answers = n; - for (i=0;ianswers[i])) - goto error; - } - n = ntohs (dns->authority_rcount); - if (n > 0) - { - p->authority_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record)); - p->num_authority_records = n; - for (i=0;iauthority_records[i])) - goto error; - } - n = ntohs (dns->additional_rcount); - if (n > 0) - { - p->additional_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record)); - p->num_additional_records = n; - for (i=0;iadditional_records[i])) - goto error; - } - return p; - error: - GNUNET_break_op (0); - GNUNET_DNSPARSER_free_packet (p); - return NULL; -} - - -/** - * Free memory taken by a packet. - * - * @param p packet to free - */ -void -GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p) -{ - unsigned int i; - - for (i=0;inum_queries;i++) - GNUNET_free_non_null (p->queries[i].name); - GNUNET_free_non_null (p->queries); - for (i=0;inum_answers;i++) - GNUNET_DNSPARSER_free_record (&p->answers[i]); - GNUNET_free_non_null (p->answers); - for (i=0;inum_authority_records;i++) - GNUNET_DNSPARSER_free_record (&p->authority_records[i]); - GNUNET_free_non_null (p->authority_records); - for (i=0;inum_additional_records;i++) - GNUNET_DNSPARSER_free_record (&p->additional_records[i]); - GNUNET_free_non_null (p->additional_records); - GNUNET_free (p); -} - - -/* ********************** DNS packet assembly code **************** */ - - -/** - * Add a DNS name to the UDP packet at the given location, converting - * the name to IDNA notation as necessary. - * - * @param dst where to write the name (UDP packet) - * @param dst_len number of bytes in @a dst - * @param off pointer to offset where to write the name (increment by bytes used) - * must not be changed if there is an error - * @param name name to write - * @return #GNUNET_SYSERR if @a name is invalid - * #GNUNET_NO if @a name did not fit - * #GNUNET_OK if @a name was added to @a dst - */ -int -GNUNET_DNSPARSER_builder_add_name (char *dst, - size_t dst_len, - size_t *off, - const char *name) -{ - const char *dot; - const char *idna_name; - char *idna_start; - size_t start; - size_t pos; - size_t len; - Idna_rc rc; - - if (NULL == name) - return GNUNET_SYSERR; - - if (IDNA_SUCCESS != - (rc = idna_to_ascii_8z (name, - &idna_start, - IDNA_ALLOW_UNASSIGNED))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Failed to convert UTF-8 name `%s' to DNS IDNA format: %s\n"), - name, - idna_strerror (rc)); - return GNUNET_NO; - } - idna_name = idna_start; - start = *off; - if (start + strlen (idna_name) + 2 > dst_len) - goto fail; - pos = start; - do - { - dot = strchr (idna_name, '.'); - if (NULL == dot) - len = strlen (idna_name); - else - len = dot - idna_name; - if ( (len >= 64) || (0 == len) ) - { - GNUNET_break (0); - goto fail; /* segment too long or empty */ - } - dst[pos++] = (char) (uint8_t) len; - GNUNET_memcpy (&dst[pos], - idna_name, - len); - pos += len; - idna_name += len + 1; /* also skip dot */ - } - while (NULL != dot); - dst[pos++] = '\0'; /* terminator */ - *off = pos; -#if WINDOWS - idn_free (idna_start); -#else - free (idna_start); -#endif - return GNUNET_OK; - fail: -#if WINDOWS - idn_free (idna_start); -#else - free (idna_start); -#endif - return GNUNET_NO; -} - - -/** - * Add a DNS query to the UDP packet at the given location. - * - * @param dst where to write the query - * @param dst_len number of bytes in @a dst - * @param off pointer to offset where to write the query (increment by bytes used) - * must not be changed if there is an error - * @param query query to write - * @return #GNUNET_SYSERR if @a query is invalid - * #GNUNET_NO if @a query did not fit - * #GNUNET_OK if @a query was added to @a dst - */ -int -GNUNET_DNSPARSER_builder_add_query (char *dst, - size_t dst_len, - size_t *off, - const struct GNUNET_DNSPARSER_Query *query) -{ - int ret; - struct GNUNET_TUN_DnsQueryLine ql; - - ret = GNUNET_DNSPARSER_builder_add_name (dst, dst_len - sizeof (struct GNUNET_TUN_DnsQueryLine), off, query->name); - if (ret != GNUNET_OK) - return ret; - ql.type = htons (query->type); - ql.dns_traffic_class = htons (query->dns_traffic_class); - GNUNET_memcpy (&dst[*off], &ql, sizeof (ql)); - (*off) += sizeof (ql); - return GNUNET_OK; -} - - -/** - * Add an MX record to the UDP packet at the given location. - * - * @param dst where to write the mx record - * @param dst_len number of bytes in @a dst - * @param off pointer to offset where to write the mx information (increment by bytes used); - * can also change if there was an error - * @param mx mx information to write - * @return #GNUNET_SYSERR if @a mx is invalid - * #GNUNET_NO if @a mx did not fit - * #GNUNET_OK if @a mx was added to @a dst - */ -int -GNUNET_DNSPARSER_builder_add_mx (char *dst, - size_t dst_len, - size_t *off, - const struct GNUNET_DNSPARSER_MxRecord *mx) -{ - uint16_t mxpref; - - if (*off + sizeof (uint16_t) > dst_len) - return GNUNET_NO; - mxpref = htons (mx->preference); - GNUNET_memcpy (&dst[*off], - &mxpref, - sizeof (mxpref)); - (*off) += sizeof (mxpref); - return GNUNET_DNSPARSER_builder_add_name (dst, - dst_len, - off, - mx->mxhost); -} - - -/** - * Add a CERT record to the UDP packet at the given location. - * - * @param dst where to write the CERT record - * @param dst_len number of bytes in @a dst - * @param off pointer to offset where to write the CERT information (increment by bytes used); - * can also change if there was an error - * @param cert CERT information to write - * @return #GNUNET_SYSERR if @a cert is invalid - * #GNUNET_NO if @a cert did not fit - * #GNUNET_OK if @a cert was added to @a dst - */ -int -GNUNET_DNSPARSER_builder_add_cert (char *dst, - size_t dst_len, - size_t *off, - const struct GNUNET_DNSPARSER_CertRecord *cert) -{ - struct GNUNET_TUN_DnsCertRecord dcert; - - if ( (cert->cert_type > UINT16_MAX) || - (cert->cert_tag > UINT16_MAX) || - (cert->algorithm > UINT8_MAX) ) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (*off + sizeof (struct GNUNET_TUN_DnsCertRecord) + cert->certificate_size > dst_len) - return GNUNET_NO; - dcert.cert_type = htons ((uint16_t) cert->cert_type); - dcert.cert_tag = htons ((uint16_t) cert->cert_tag); - dcert.algorithm = (uint8_t) cert->algorithm; - GNUNET_memcpy (&dst[*off], &dcert, sizeof (dcert)); - (*off) += sizeof (dcert); - GNUNET_memcpy (&dst[*off], cert->certificate_data, cert->certificate_size); - (*off) += cert->certificate_size; - return GNUNET_OK; -} - - -/** - * Add an SOA record to the UDP packet at the given location. - * - * @param dst where to write the SOA record - * @param dst_len number of bytes in @a dst - * @param off pointer to offset where to write the SOA information (increment by bytes used) - * can also change if there was an error - * @param soa SOA information to write - * @return #GNUNET_SYSERR if @a soa is invalid - * #GNUNET_NO if @a soa did not fit - * #GNUNET_OK if @a soa was added to @a dst - */ -int -GNUNET_DNSPARSER_builder_add_soa (char *dst, - size_t dst_len, - size_t *off, - const struct GNUNET_DNSPARSER_SoaRecord *soa) -{ - struct GNUNET_TUN_DnsSoaRecord sd; - int ret; - - if ( (GNUNET_OK != (ret = GNUNET_DNSPARSER_builder_add_name (dst, - dst_len, - off, - soa->mname))) || - (GNUNET_OK != (ret = GNUNET_DNSPARSER_builder_add_name (dst, - dst_len, - off, - soa->rname)) ) ) - return ret; - if (*off + sizeof (struct GNUNET_TUN_DnsSoaRecord) > dst_len) - return GNUNET_NO; - sd.serial = htonl (soa->serial); - sd.refresh = htonl (soa->refresh); - sd.retry = htonl (soa->retry); - sd.expire = htonl (soa->expire); - sd.minimum = htonl (soa->minimum_ttl); - GNUNET_memcpy (&dst[*off], &sd, sizeof (sd)); - (*off) += sizeof (sd); - return GNUNET_OK; -} - - -/** - * Add an SRV record to the UDP packet at the given location. - * - * @param dst where to write the SRV record - * @param dst_len number of bytes in @a dst - * @param off pointer to offset where to write the SRV information (increment by bytes used) - * can also change if there was an error - * @param srv SRV information to write - * @return #GNUNET_SYSERR if @a srv is invalid - * #GNUNET_NO if @a srv did not fit - * #GNUNET_OK if @a srv was added to @a dst - */ -int -GNUNET_DNSPARSER_builder_add_srv (char *dst, - size_t dst_len, - size_t *off, - const struct GNUNET_DNSPARSER_SrvRecord *srv) -{ - struct GNUNET_TUN_DnsSrvRecord sd; - int ret; - - if (*off + sizeof (struct GNUNET_TUN_DnsSrvRecord) > dst_len) - return GNUNET_NO; - sd.prio = htons (srv->priority); - sd.weight = htons (srv->weight); - sd.port = htons (srv->port); - GNUNET_memcpy (&dst[*off], &sd, sizeof (sd)); - (*off) += sizeof (sd); - if (GNUNET_OK != (ret = GNUNET_DNSPARSER_builder_add_name (dst, - dst_len, - off, - srv->target))) - return ret; - return GNUNET_OK; -} - - -/** - * Add a DNS record to the UDP packet at the given location. - * - * @param dst where to write the query - * @param dst_len number of bytes in @a dst - * @param off pointer to offset where to write the query (increment by bytes used) - * must not be changed if there is an error - * @param record record to write - * @return #GNUNET_SYSERR if @a record is invalid - * #GNUNET_NO if @a record did not fit - * #GNUNET_OK if @a record was added to @a dst - */ -static int -add_record (char *dst, - size_t dst_len, - size_t *off, - const struct GNUNET_DNSPARSER_Record *record) -{ - int ret; - size_t start; - size_t pos; - struct GNUNET_TUN_DnsRecordLine rl; - - start = *off; - ret = GNUNET_DNSPARSER_builder_add_name (dst, - dst_len - sizeof (struct GNUNET_TUN_DnsRecordLine), - off, - record->name); - if (GNUNET_OK != ret) - return ret; - /* '*off' is now the position where we will need to write the record line */ - - pos = *off + sizeof (struct GNUNET_TUN_DnsRecordLine); - switch (record->type) - { - case GNUNET_DNSPARSER_TYPE_MX: - ret = GNUNET_DNSPARSER_builder_add_mx (dst, - dst_len, - &pos, - record->data.mx); - break; - case GNUNET_DNSPARSER_TYPE_CERT: - ret = GNUNET_DNSPARSER_builder_add_cert (dst, - dst_len, - &pos, - record->data.cert); - break; - case GNUNET_DNSPARSER_TYPE_SOA: - ret = GNUNET_DNSPARSER_builder_add_soa (dst, - dst_len, - &pos, - record->data.soa); - break; - case GNUNET_DNSPARSER_TYPE_NS: - case GNUNET_DNSPARSER_TYPE_CNAME: - case GNUNET_DNSPARSER_TYPE_PTR: - ret = GNUNET_DNSPARSER_builder_add_name (dst, - dst_len, - &pos, - record->data.hostname); - break; - case GNUNET_DNSPARSER_TYPE_SRV: - ret = GNUNET_DNSPARSER_builder_add_srv (dst, - dst_len, - &pos, - record->data.srv); - break; - default: - if (pos + record->data.raw.data_len > dst_len) - { - ret = GNUNET_NO; - break; - } - GNUNET_memcpy (&dst[pos], - record->data.raw.data, - record->data.raw.data_len); - pos += record->data.raw.data_len; - ret = GNUNET_OK; - break; - } - if (GNUNET_OK != ret) - { - *off = start; - return GNUNET_NO; - } - - if (pos - (*off + sizeof (struct GNUNET_TUN_DnsRecordLine)) > UINT16_MAX) - { - /* record data too long */ - *off = start; - return GNUNET_NO; - } - rl.type = htons (record->type); - rl.dns_traffic_class = htons (record->dns_traffic_class); - rl.ttl = htonl (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value_us / 1000LL / 1000LL); /* in seconds */ - rl.data_len = htons ((uint16_t) (pos - (*off + sizeof (struct GNUNET_TUN_DnsRecordLine)))); - GNUNET_memcpy (&dst[*off], &rl, sizeof (struct GNUNET_TUN_DnsRecordLine)); - *off = pos; - return GNUNET_OK; -} - - -/** - * Given a DNS packet @a p, generate the corresponding UDP payload. - * Note that we do not attempt to pack the strings with pointers - * as this would complicate the code and this is about being - * simple and secure, not fast, fancy and broken like bind. - * - * @param p packet to pack - * @param max maximum allowed size for the resulting UDP payload - * @param buf set to a buffer with the packed message - * @param buf_length set to the length of @a buf - * @return #GNUNET_SYSERR if @a p is invalid - * #GNUNET_NO if @a p was truncated (but there is still a result in @a buf) - * #GNUNET_OK if @a p was packed completely into @a buf - */ -int -GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p, - uint16_t max, - char **buf, - size_t *buf_length) -{ - struct GNUNET_TUN_DnsHeader dns; - size_t off; - char tmp[max]; - unsigned int i; - int ret; - int trc; - - if ( (p->num_queries > UINT16_MAX) || - (p->num_answers > UINT16_MAX) || - (p->num_authority_records > UINT16_MAX) || - (p->num_additional_records > UINT16_MAX) ) - return GNUNET_SYSERR; - dns.id = p->id; - dns.flags = p->flags; - dns.query_count = htons (p->num_queries); - dns.answer_rcount = htons (p->num_answers); - dns.authority_rcount = htons (p->num_authority_records); - dns.additional_rcount = htons (p->num_additional_records); - - off = sizeof (struct GNUNET_TUN_DnsHeader); - trc = GNUNET_NO; - for (i=0;inum_queries;i++) - { - ret = GNUNET_DNSPARSER_builder_add_query (tmp, - sizeof (tmp), - &off, - &p->queries[i]); - if (GNUNET_SYSERR == ret) - return GNUNET_SYSERR; - if (GNUNET_NO == ret) - { - dns.query_count = htons ((uint16_t) (i-1)); - trc = GNUNET_YES; - break; - } - } - for (i=0;inum_answers;i++) - { - ret = add_record (tmp, - sizeof (tmp), - &off, - &p->answers[i]); - if (GNUNET_SYSERR == ret) - return GNUNET_SYSERR; - if (GNUNET_NO == ret) - { - dns.answer_rcount = htons ((uint16_t) (i-1)); - trc = GNUNET_YES; - break; - } - } - for (i=0;inum_authority_records;i++) - { - ret = add_record (tmp, - sizeof (tmp), - &off, - &p->authority_records[i]); - if (GNUNET_SYSERR == ret) - return GNUNET_SYSERR; - if (GNUNET_NO == ret) - { - dns.authority_rcount = htons ((uint16_t) (i-1)); - trc = GNUNET_YES; - break; - } - } - for (i=0;inum_additional_records;i++) - { - ret = add_record (tmp, - sizeof (tmp), - &off, - &p->additional_records[i]); - if (GNUNET_SYSERR == ret) - return GNUNET_SYSERR; - if (GNUNET_NO == ret) - { - dns.additional_rcount = htons (i-1); - trc = GNUNET_YES; - break; - } - } - - if (GNUNET_YES == trc) - dns.flags.message_truncated = 1; - GNUNET_memcpy (tmp, - &dns, - sizeof (struct GNUNET_TUN_DnsHeader)); - - *buf = GNUNET_malloc (off); - *buf_length = off; - GNUNET_memcpy (*buf, - tmp, - off); - if (GNUNET_YES == trc) - return GNUNET_NO; - return GNUNET_OK; -} - - -/** - * Convert a block of binary data to HEX. - * - * @param data binary data to convert - * @param data_size number of bytes in @a data - * @return HEX string (lower case) - */ -char * -GNUNET_DNSPARSER_bin_to_hex (const void *data, - size_t data_size) -{ - char *ret; - size_t off; - const uint8_t *idata; - - idata = data; - ret = GNUNET_malloc (data_size * 2 + 1); - for (off = 0; off < data_size; off++) - sprintf (&ret[off * 2], - "%02x", - idata[off]); - return ret; -} - - -/** - * Convert a HEX string to block of binary data. - * - * @param hex HEX string to convert (may contain mixed case) - * @param data where to write result, must be - * at least `strlen(hex)/2` bytes long - * @return number of bytes written to data - */ -size_t -GNUNET_DNSPARSER_hex_to_bin (const char *hex, - void *data) -{ - size_t data_size; - size_t off; - uint8_t *idata; - unsigned int h; - char in[3]; - - data_size = strlen (hex) / 2; - idata = data; - in[2] = '\0'; - for (off = 0; off < data_size; off++) - { - in[0] = tolower ((unsigned char) hex[off * 2]); - in[1] = tolower ((unsigned char) hex[off * 2 + 1]); - if (1 != sscanf (in, "%x", &h)) - return off; - idata[off] = (uint8_t) h; - } - return off; -} - - -/* end of dnsparser.c */ diff --git a/src/dns/dnsstub.c b/src/dns/dnsstub.c deleted file mode 100644 index 969ff7beb..000000000 --- a/src/dns/dnsstub.c +++ /dev/null @@ -1,749 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012, 2018 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ -/** - * @file dns/dnsstub.c - * @brief DNS stub resolver which sends DNS requests to an actual resolver - * @author Christian Grothoff - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_tun_lib.h" -#include "gnunet_dnsstub_lib.h" - -/** - * Timeout for retrying DNS queries. - */ -#define DNS_RETRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250) - - -/** - * DNS Server used for resolution. - */ -struct DnsServer; - - -/** - * UDP socket we are using for sending DNS requests to the Internet. - */ -struct GNUNET_DNSSTUB_RequestSocket -{ - - /** - * UDP socket we use for this request for IPv4 - */ - struct GNUNET_NETWORK_Handle *dnsout4; - - /** - * UDP socket we use for this request for IPv6 - */ - struct GNUNET_NETWORK_Handle *dnsout6; - - /** - * Function to call with result. - */ - GNUNET_DNSSTUB_ResultCallback rc; - - /** - * Closure for @e rc. - */ - void *rc_cls; - - /** - * Task for reading from dnsout4 and dnsout6. - */ - struct GNUNET_SCHEDULER_Task *read_task; - - /** - * Task for retrying transmission of the query. - */ - struct GNUNET_SCHEDULER_Task *retry_task; - - /** - * Next address we sent the DNS request to. - */ - struct DnsServer *ds_pos; - - /** - * Context this request executes in. - */ - struct GNUNET_DNSSTUB_Context *ctx; - - /** - * Query we sent to @e addr. - */ - void *request; - - /** - * Number of bytes in @a request. - */ - size_t request_len; - -}; - - -/** - * DNS Server used for resolution. - */ -struct DnsServer -{ - - /** - * Kept in a DLL. - */ - struct DnsServer *next; - - /** - * Kept in a DLL. - */ - struct DnsServer *prev; - - /** - * IP address of the DNS resolver. - */ - struct sockaddr_storage ss; -}; - - -/** - * Handle to the stub resolver. - */ -struct GNUNET_DNSSTUB_Context -{ - - /** - * Array of all open sockets for DNS requests. - */ - struct GNUNET_DNSSTUB_RequestSocket *sockets; - - /** - * DLL of DNS resolvers we use. - */ - struct DnsServer *dns_head; - - /** - * DLL of DNS resolvers we use. - */ - struct DnsServer *dns_tail; - - /** - * How frequently do we retry requests? - */ - struct GNUNET_TIME_Relative retry_freq; - - /** - * Length of @e sockets array. - */ - unsigned int num_sockets; - -}; - - -/** - * We're done with a `struct GNUNET_DNSSTUB_RequestSocket`, close it for now. - * - * @param rs request socket to clean up - */ -static void -cleanup_rs (struct GNUNET_DNSSTUB_RequestSocket *rs) -{ - if (NULL != rs->dnsout4) - { - GNUNET_NETWORK_socket_close (rs->dnsout4); - rs->dnsout4 = NULL; - } - if (NULL != rs->dnsout6) - { - GNUNET_NETWORK_socket_close (rs->dnsout6); - rs->dnsout6 = NULL; - } - if (NULL != rs->read_task) - { - GNUNET_SCHEDULER_cancel (rs->read_task); - rs->read_task = NULL; - } - if (NULL != rs->retry_task) - { - GNUNET_SCHEDULER_cancel (rs->retry_task); - rs->retry_task = NULL; - } - if (NULL != rs->request) - { - GNUNET_free (rs->request); - rs->request = NULL; - } -} - - -/** - * Open source port for sending DNS requests - * - * @param af AF_INET or AF_INET6 - * @return #GNUNET_OK on success - */ -static struct GNUNET_NETWORK_Handle * -open_socket (int af) -{ - struct sockaddr_in a4; - struct sockaddr_in6 a6; - struct sockaddr *sa; - socklen_t alen; - struct GNUNET_NETWORK_Handle *ret; - - ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0); - if (NULL == ret) - return NULL; - switch (af) - { - case AF_INET: - memset (&a4, 0, alen = sizeof (struct sockaddr_in)); - sa = (struct sockaddr *) &a4; - break; - case AF_INET6: - memset (&a6, 0, alen = sizeof (struct sockaddr_in6)); - sa = (struct sockaddr *) &a6; - break; - default: - GNUNET_break (0); - GNUNET_NETWORK_socket_close (ret); - return NULL; - } - sa->sa_family = af; - if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret, - sa, - alen)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Could not bind to any port: %s\n"), - STRERROR (errno)); - GNUNET_NETWORK_socket_close (ret); - return NULL; - } - return ret; -} - - -/** - * Get a socket of the specified address family to send out a - * UDP DNS request to the Internet. - * - * @param ctx the DNSSTUB context - * @return NULL on error - */ -static struct GNUNET_DNSSTUB_RequestSocket * -get_request_socket (struct GNUNET_DNSSTUB_Context *ctx) -{ - struct GNUNET_DNSSTUB_RequestSocket *rs; - - for (unsigned int i=0;i<256;i++) - { - rs = &ctx->sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, - ctx->num_sockets)]; - if (NULL == rs->rc) - break; - } - if (NULL != rs->rc) - { - /* signal "failure" */ - rs->rc (rs->rc_cls, - NULL, - 0); - rs->rc = NULL; - } - if (NULL != rs->read_task) - { - GNUNET_SCHEDULER_cancel (rs->read_task); - rs->read_task = NULL; - } - if (NULL != rs->retry_task) - { - GNUNET_SCHEDULER_cancel (rs->retry_task); - rs->retry_task = NULL; - } - if (NULL != rs->request) - { - GNUNET_free (rs->request); - rs->request = NULL; - } - rs->ctx = ctx; - return rs; -} - - -/** - * Actually do the reading of a DNS packet from our UDP socket and see - * if we have a valid, matching, pending request. - * - * @param rs request socket with callback details - * @param dnsout socket to read from - * @return #GNUNET_OK on success, #GNUNET_NO on drop, #GNUNET_SYSERR on IO-errors (closed socket) - */ -static int -do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs, - struct GNUNET_NETWORK_Handle *dnsout) -{ - struct GNUNET_DNSSTUB_Context *ctx = rs->ctx; - ssize_t r; - int len; - -#ifndef MINGW - if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), - FIONREAD, - &len)) - { - /* conservative choice: */ - len = UINT16_MAX; - } -#else - /* port the code above? */ - len = UINT16_MAX; -#endif - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Receiving %d byte DNS reply\n", - len); - { - unsigned char buf[len] GNUNET_ALIGN; - int found; - struct sockaddr_storage addr; - socklen_t addrlen; - struct GNUNET_TUN_DnsHeader *dns; - - addrlen = sizeof (addr); - memset (&addr, - 0, - sizeof (addr)); - r = GNUNET_NETWORK_socket_recvfrom (dnsout, - buf, - sizeof (buf), - (struct sockaddr*) &addr, - &addrlen); - if (-1 == r) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, - "recvfrom"); - GNUNET_NETWORK_socket_close (dnsout); - return GNUNET_SYSERR; - } - found = GNUNET_NO; - for (struct DnsServer *ds = ctx->dns_head; NULL != ds; ds = ds->next) - { - if (0 == memcmp (&addr, - &ds->ss, - GNUNET_MIN (sizeof (struct sockaddr_storage), - addrlen))) - { - found = GNUNET_YES; - break; - } - } - if (GNUNET_NO == found) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received DNS response from server we never asked (ignored)"); - return GNUNET_NO; - } - if (sizeof (struct GNUNET_TUN_DnsHeader) > r) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Received DNS response that is too small (%u bytes)"), - (unsigned int) r); - return GNUNET_NO; - } - dns = (struct GNUNET_TUN_DnsHeader *) buf; - if (NULL == rs->rc) - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Request timeout or cancelled; ignoring reply\n"); - return GNUNET_NO; - } - rs->rc (rs->rc_cls, - dns, - r); - } - return GNUNET_OK; -} - - -/** - * Read a DNS response from the (unhindered) UDP-Socket - * - * @param cls socket to read from - */ -static void -read_response (void *cls); - - -/** - * Schedule #read_response() task for @a rs. - * - * @param rs request to schedule read operation for - */ -static void -schedule_read (struct GNUNET_DNSSTUB_RequestSocket *rs) -{ - struct GNUNET_NETWORK_FDSet *rset; - - if (NULL != rs->read_task) - GNUNET_SCHEDULER_cancel (rs->read_task); - rset = GNUNET_NETWORK_fdset_create (); - if (NULL != rs->dnsout4) - GNUNET_NETWORK_fdset_set (rset, - rs->dnsout4); - if (NULL != rs->dnsout6) - GNUNET_NETWORK_fdset_set (rset, - rs->dnsout6); - rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, - GNUNET_TIME_UNIT_FOREVER_REL, - rset, - NULL, - &read_response, - rs); - GNUNET_NETWORK_fdset_destroy (rset); -} - - -/** - * Read a DNS response from the (unhindered) UDP-Socket - * - * @param cls `struct GNUNET_DNSSTUB_RequestSocket` to read from - */ -static void -read_response (void *cls) -{ - struct GNUNET_DNSSTUB_RequestSocket *rs = cls; - const struct GNUNET_SCHEDULER_TaskContext *tc; - - rs->read_task = NULL; - tc = GNUNET_SCHEDULER_get_task_context (); - /* read and process ready sockets */ - if ( (NULL != rs->dnsout4) && - (GNUNET_NETWORK_fdset_isset (tc->read_ready, - rs->dnsout4)) && - (GNUNET_SYSERR == - do_dns_read (rs, - rs->dnsout4)) ) - rs->dnsout4 = NULL; - if ( (NULL != rs->dnsout6) && - (GNUNET_NETWORK_fdset_isset (tc->read_ready, - rs->dnsout6)) && - (GNUNET_SYSERR == - do_dns_read (rs, - rs->dnsout6)) ) - rs->dnsout6 = NULL; - /* re-schedule read task */ - schedule_read (rs); -} - - -/** - * Task to (re)transmit the DNS query, possibly repeatedly until - * we succeed. - * - * @param cls our `struct GNUNET_DNSSTUB_RequestSocket *` - */ -static void -transmit_query (void *cls) -{ - struct GNUNET_DNSSTUB_RequestSocket *rs = cls; - struct GNUNET_DNSSTUB_Context *ctx = rs->ctx; - const struct sockaddr *sa; - socklen_t salen; - struct DnsServer *ds; - struct GNUNET_NETWORK_Handle *dnsout; - - rs->retry_task = GNUNET_SCHEDULER_add_delayed (ctx->retry_freq, - &transmit_query, - rs); - ds = rs->ds_pos; - rs->ds_pos = ds->next; - if (NULL == rs->ds_pos) - rs->ds_pos = ctx->dns_head; - GNUNET_assert (NULL != ds); - dnsout = NULL; - switch (ds->ss.ss_family) - { - case AF_INET: - if (NULL == rs->dnsout4) - rs->dnsout4 = open_socket (AF_INET); - dnsout = rs->dnsout4; - sa = (const struct sockaddr *) &ds->ss; - salen = sizeof (struct sockaddr_in); - break; - case AF_INET6: - if (NULL == rs->dnsout6) - rs->dnsout6 = open_socket (AF_INET6); - dnsout = rs->dnsout6; - sa = (const struct sockaddr *) &ds->ss; - salen = sizeof (struct sockaddr_in6); - break; - default: - return; - } - if (NULL == dnsout) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to use configure DNS server, skipping\n"); - return; - } - if (GNUNET_SYSERR == - GNUNET_NETWORK_socket_sendto (dnsout, - rs->request, - rs->request_len, - sa, - salen)) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Failed to send DNS request to %s: %s\n"), - GNUNET_a2s (sa, - salen), - STRERROR (errno)); - else - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Sent DNS request to %s\n"), - GNUNET_a2s (sa, - salen)); - schedule_read (rs); -} - - -/** - * Perform DNS resolution using our default IP from init. - * - * @param ctx stub resolver to use - * @param request DNS request to transmit - * @param request_len number of bytes in msg - * @param rc function to call with result - * @param rc_cls closure for 'rc' - * @return socket used for the request, NULL on error - */ -struct GNUNET_DNSSTUB_RequestSocket * -GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx, - const void *request, - size_t request_len, - GNUNET_DNSSTUB_ResultCallback rc, - void *rc_cls) -{ - struct GNUNET_DNSSTUB_RequestSocket *rs; - - if (NULL == ctx->dns_head) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No DNS server configured for resolution\n"); - return NULL; - } - if (NULL == (rs = get_request_socket (ctx))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No request socket available for DNS resolution\n"); - return NULL; - } - rs->ds_pos = ctx->dns_head; - rs->rc = rc; - rs->rc_cls = rc_cls; - rs->request = GNUNET_memdup (request, - request_len); - rs->request_len = request_len; - rs->retry_task = GNUNET_SCHEDULER_add_now (&transmit_query, - rs); - return rs; -} - - -/** - * Cancel DNS resolution. - * - * @param rs resolution to cancel - */ -void -GNUNET_DNSSTUB_resolve_cancel (struct GNUNET_DNSSTUB_RequestSocket *rs) -{ - rs->rc = NULL; - if (NULL != rs->retry_task) - { - GNUNET_SCHEDULER_cancel (rs->retry_task); - rs->retry_task = NULL; - } - if (NULL != rs->read_task) - { - GNUNET_SCHEDULER_cancel (rs->read_task); - rs->read_task = NULL; - } -} - - -/** - * Start a DNS stub resolver. - * - * @param num_sockets how many sockets should we open - * in parallel for DNS queries for this stub? - * @return NULL on error - */ -struct GNUNET_DNSSTUB_Context * -GNUNET_DNSSTUB_start (unsigned int num_sockets) -{ - struct GNUNET_DNSSTUB_Context *ctx; - - if (0 == num_sockets) - { - GNUNET_break (0); - return NULL; - } - ctx = GNUNET_new (struct GNUNET_DNSSTUB_Context); - ctx->num_sockets = num_sockets; - ctx->sockets = GNUNET_new_array (num_sockets, - struct GNUNET_DNSSTUB_RequestSocket); - ctx->retry_freq = DNS_RETRANSMIT_DELAY; - return ctx; -} - - -/** - * Add nameserver for use by the DNSSTUB. We will use - * all provided nameservers for resolution (round-robin). - * - * @param ctx resolver context to modify - * @param dns_ip target IP address to use (as string) - * @return #GNUNET_OK on success - */ -int -GNUNET_DNSSTUB_add_dns_ip (struct GNUNET_DNSSTUB_Context *ctx, - const char *dns_ip) -{ - struct DnsServer *ds; - struct in_addr i4; - struct in6_addr i6; - - ds = GNUNET_new (struct DnsServer); - if (1 == inet_pton (AF_INET, - dns_ip, - &i4)) - { - struct sockaddr_in *s4 = (struct sockaddr_in *) &ds->ss; - - s4->sin_family = AF_INET; - s4->sin_port = htons (53); - s4->sin_addr = i4; -#if HAVE_SOCKADDR_IN_SIN_LEN - s4->sin_len = (u_char) sizeof (struct sockaddr_in); -#endif - } - else if (1 == inet_pton (AF_INET6, - dns_ip, - &i6)) - { - struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &ds->ss; - - s6->sin6_family = AF_INET6; - s6->sin6_port = htons (53); - s6->sin6_addr = i6; -#if HAVE_SOCKADDR_IN_SIN_LEN - s6->sin6_len = (u_char) sizeof (struct sockaddr_in6); -#endif - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Malformed IP address `%s' for DNS server\n", - dns_ip); - GNUNET_free (ds); - return GNUNET_SYSERR; - } - GNUNET_CONTAINER_DLL_insert (ctx->dns_head, - ctx->dns_tail, - ds); - return GNUNET_OK; -} - - -/** - * Add nameserver for use by the DNSSTUB. We will use - * all provided nameservers for resolution (round-robin). - * - * @param ctx resolver context to modify - * @param sa socket address of DNS resolver to use - * @return #GNUNET_OK on success - */ -int -GNUNET_DNSSTUB_add_dns_sa (struct GNUNET_DNSSTUB_Context *ctx, - const struct sockaddr *sa) -{ - struct DnsServer *ds; - - ds = GNUNET_new (struct DnsServer); - switch (sa->sa_family) - { - case AF_INET: - GNUNET_memcpy (&ds->ss, - sa, - sizeof (struct sockaddr_in)); - break; - case AF_INET6: - GNUNET_memcpy (&ds->ss, - sa, - sizeof (struct sockaddr_in6)); - break; - default: - GNUNET_break (0); - GNUNET_free (ds); - return GNUNET_SYSERR; - } - GNUNET_CONTAINER_DLL_insert (ctx->dns_head, - ctx->dns_tail, - ds); - return GNUNET_OK; -} - - -/** - * How long should we try requests before timing out? - * Only effective for requests issued after this call. - * - * @param ctx resolver context to modify - * @param retry_freq how long to wait between retries - */ -void -GNUNET_DNSSTUB_set_retry (struct GNUNET_DNSSTUB_Context *ctx, - struct GNUNET_TIME_Relative retry_freq) -{ - ctx->retry_freq = retry_freq; -} - - -/** - * Cleanup DNSSTUB resolver. - * - * @param ctx stub resolver to clean up - */ -void -GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx) -{ - struct DnsServer *ds; - - while (NULL != (ds = ctx->dns_head)) - { - GNUNET_CONTAINER_DLL_remove (ctx->dns_head, - ctx->dns_tail, - ds); - GNUNET_free (ds); - } - for (unsigned int i=0;inum_sockets;i++) - cleanup_rs (&ctx->sockets[i]); - GNUNET_free (ctx->sockets); - GNUNET_free (ctx); -} - - -/* end of dnsstub.c */ diff --git a/src/tun/regex.c b/src/tun/regex.c deleted file mode 100644 index 7565a9eac..000000000 --- a/src/tun/regex.c +++ /dev/null @@ -1,834 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2012, 2013, 2015 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ -/** - * @file src/tun/regex.c - * @brief functions to convert IP networks to regexes - * @author Maximilian Szengel - * @author Christian Grothoff - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_tun_lib.h" - -/** - * 'wildcard', matches all possible values (for HEX encoding). - */ -#define DOT "(0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)" - - -/** - * Create a regex in @a rxstr from the given @a ip and @a netmask. - * - * @param ip IPv4 representation. - * @param port destination port - * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV4_REGEXLEN - * bytes long. - */ -void -GNUNET_TUN_ipv4toregexsearch (const struct in_addr *ip, - uint16_t port, - char *rxstr) -{ - GNUNET_snprintf (rxstr, - GNUNET_TUN_IPV4_REGEXLEN, - "4-%04X-%08X", - (unsigned int) port, - ntohl (ip->s_addr)); -} - - -/** - * Create a regex in @a rxstr from the given @a ipv6 and @a prefixlen. - * - * @param ipv6 IPv6 representation. - * @param port destination port - * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV6_REGEXLEN - * bytes long. - */ -void -GNUNET_TUN_ipv6toregexsearch (const struct in6_addr *ipv6, - uint16_t port, - char *rxstr) -{ - const uint32_t *addr; - - addr = (const uint32_t *) ipv6; - GNUNET_snprintf (rxstr, - GNUNET_TUN_IPV6_REGEXLEN, - "6-%04X-%08X%08X%08X%08X", - (unsigned int) port, - ntohl (addr[0]), - ntohl (addr[1]), - ntohl (addr[2]), - ntohl (addr[3])); -} - - -/** - * Convert the given 4-bit (!) number to a regex. - * - * @param value the value, only the lowest 4 bits will be looked at - * @param mask which bits in value are wildcards (any value)? - */ -static char * -nibble_to_regex (uint8_t value, - uint8_t mask) -{ - char *ret; - - value &= mask; - switch (mask) - { - case 0: - return GNUNET_strdup (DOT); - case 8: - GNUNET_asprintf (&ret, - "(%X|%X|%X|%X|%X|%X|%X|%X)", - value, - value + 1, - value + 2, - value + 3, - value + 4, - value + 5, - value + 6, - value + 7); - return ret; - case 12: - GNUNET_asprintf (&ret, - "(%X|%X|%X|%X)", - value, - value + 1, - value + 2, - value + 3); - return ret; - case 14: - GNUNET_asprintf (&ret, - "(%X|%X)", - value, - value + 1); - return ret; - case 15: - GNUNET_asprintf (&ret, - "%X", - value); - return ret; - default: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Bad mask: %d\n"), - mask); - GNUNET_break (0); - return NULL; - } -} - - -/** - * Convert the given 16-bit number to a regex. - * - * @param value the value - * @param mask which bits in value are wildcards (any value)? - */ -static char * -num_to_regex (uint16_t value, - uint16_t mask) -{ - const uint8_t *v = (const uint8_t *) &value; - const uint8_t *m = (const uint8_t *) &mask; - char *a; - char *b; - char *c; - char *d; - char *ret; - - a = nibble_to_regex (v[0] >> 4, m[0] >> 4); - b = nibble_to_regex (v[0] & 15, m[0] & 15); - c = nibble_to_regex (v[1] >> 4, m[1] >> 4); - d = nibble_to_regex (v[1] & 15, m[1] & 15); - ret = NULL; - if ( (NULL != a) && - (NULL != b) && - (NULL != c) && - (NULL != d) ) - GNUNET_asprintf (&ret, - "%s%s%s%s", - a, b, c, d); - GNUNET_free_non_null (a); - GNUNET_free_non_null (b); - GNUNET_free_non_null (c); - GNUNET_free_non_null (d); - return ret; -} - - -/** - * Do we need to put parents around the given argument? - * - * @param arg part of a regular expression - * @return #GNUNET_YES if we should parens, - * #GNUNET_NO if not - */ -static int -needs_parens (const char *arg) -{ - size_t off; - size_t len; - unsigned int op; - - op = 0; - len = strlen (arg); - for (off=0;off 0); - op--; - break; - case '|': - if (0 == op) - return GNUNET_YES; - break; - default: - break; - } - } - return GNUNET_NO; -} - - -/** - * Compute port policy for the given range of - * port numbers. - * - * @param start starting offset - * @param end end offset - * @param step increment level (power of 16) - * @param pp port policy to convert - * @return corresponding regex - */ -static char * -compute_policy (unsigned int start, - unsigned int end, - unsigned int step, - const struct GNUNET_STRINGS_PortPolicy *pp) -{ - unsigned int i; - char before[36]; /* 16 * 2 + 3 dots + 0-terminator */ - char middlel[33]; /* 16 * 2 + 0-terminator */ - char middleh[33]; /* 16 * 2 + 0-terminator */ - char after[36]; /* 16 * 2 + 3 dots + 0-terminator */ - char beforep[36+2]; /* 16 * 2 + 3 dots + 0-terminator + ()*/ - char middlehp[33+2]; /* 16 * 2 + 0-terminator + () */ - char middlelp[33+2]; /* 16 * 2 + 0-terminator + () */ - char afterp[36+2]; /* 16 * 2 + 3 dots + 0-terminator + () */ - char dots[5 * strlen (DOT)]; - char buf[3]; - char *middle; - char *ret; - unsigned int xstep; - char *recl; - char *rech; - char *reclp; - char *rechp; - unsigned int start_port; - unsigned int end_port; - - GNUNET_assert (GNUNET_YES == pp->negate_portrange); - start_port = pp->start_port; - if (1 == start_port) - start_port = 0; - end_port = pp->end_port; - GNUNET_assert ((end - start) / step <= 0xF); - before[0] = '\0'; - middlel[0] = '\0'; - middleh[0] = '\0'; - after[0] = '\0'; - for (i=start;i<=end;i+=step) - { - GNUNET_snprintf (buf, - sizeof (buf), - "%X|", - (i - start) / step); - if (i / step < start_port / step) - strcat (before, buf); - else if (i / step > end_port / step) - strcat (after, buf); - else if (i / step == start_port / step) - strcat (middlel, buf); - else if (i / step == end_port / step) - strcat (middleh, buf); - } - if (strlen (before) > 0) - before[strlen (before)-1] = '\0'; - if (strlen (middlel) > 0) - middlel[strlen (middlel)-1] = '\0'; - if (strlen (middleh) > 0) - middleh[strlen (middleh)-1] = '\0'; - if (strlen (after) > 0) - after[strlen (after)-1] = '\0'; - if (needs_parens (before)) - GNUNET_snprintf (beforep, - sizeof (beforep), - "(%s)", - before); - else - strcpy (beforep, before); - if (needs_parens (middlel)) - GNUNET_snprintf (middlelp, - sizeof (middlelp), - "(%s)", - middlel); - else - strcpy (middlelp, middlel); - if (needs_parens (middleh)) - GNUNET_snprintf (middlehp, - sizeof (middlehp), - "(%s)", - middleh); - else - strcpy (middlehp, middleh); - if (needs_parens (after)) - GNUNET_snprintf (afterp, - sizeof (afterp), - "(%s)", - after); - else - strcpy (afterp, after); - dots[0] = '\0'; - for (xstep=step/16;xstep>0;xstep/=16) - strcat (dots, DOT); - if (step >= 16) - { - if (strlen (middlel) > 0) - recl = compute_policy ((start_port / step) * step, - (start_port / step) * step + step - 1, - step / 16, - pp); - else - recl = GNUNET_strdup (""); - if (strlen (middleh) > 0) - rech = compute_policy ((end_port / step) * step, - (end_port / step) * step + step - 1, - step / 16, - pp); - else - rech = GNUNET_strdup (""); - } - else - { - recl = GNUNET_strdup (""); - rech = GNUNET_strdup (""); - middlel[0] = '\0'; - middlelp[0] = '\0'; - middleh[0] = '\0'; - middlehp[0] = '\0'; - } - if (needs_parens (recl)) - GNUNET_asprintf (&reclp, - "(%s)", - recl); - else - reclp = GNUNET_strdup (recl); - if (needs_parens (rech)) - GNUNET_asprintf (&rechp, - "(%s)", - rech); - else - rechp = GNUNET_strdup (rech); - - if ( (strlen (middleh) > 0) && - (strlen (rech) > 0) && - (strlen (middlel) > 0) && - (strlen (recl) > 0) ) - { - GNUNET_asprintf (&middle, - "%s%s|%s%s", - middlel, - reclp, - middleh, - rechp); - } - else if ( (strlen (middleh) > 0) && - (strlen (rech) > 0) ) - { - GNUNET_asprintf (&middle, - "%s%s", - middleh, - rechp); - } - else if ( (strlen (middlel) > 0) && - (strlen (recl) > 0) ) - { - GNUNET_asprintf (&middle, - "%s%s", - middlel, - reclp); - } - else - { - middle = GNUNET_strdup (""); - } - if ( (strlen(before) > 0) && - (strlen(after) > 0) ) - { - if (strlen (dots) > 0) - { - if (strlen (middle) > 0) - GNUNET_asprintf (&ret, - "(%s%s|%s|%s%s)", - beforep, dots, - middle, - afterp, dots); - else - GNUNET_asprintf (&ret, - "(%s|%s)%s", - beforep, - afterp, - dots); - } - else - { - if (strlen (middle) > 0) - GNUNET_asprintf (&ret, - "(%s|%s|%s)", - before, - middle, - after); - else if (1 == step) - GNUNET_asprintf (&ret, - "%s|%s", - before, - after); - else - GNUNET_asprintf (&ret, - "(%s|%s)", - before, - after); - } - } - else if (strlen (before) > 0) - { - if (strlen (dots) > 0) - { - if (strlen (middle) > 0) - GNUNET_asprintf (&ret, - "(%s%s|%s)", - beforep, dots, - middle); - else - GNUNET_asprintf (&ret, - "%s%s", - beforep, dots); - } - else - { - if (strlen (middle) > 0) - GNUNET_asprintf (&ret, - "(%s|%s)", - before, - middle); - else - GNUNET_asprintf (&ret, - "%s", - before); - } - } - else if (strlen (after) > 0) - { - if (strlen (dots) > 0) - { - if (strlen (middle) > 0) - GNUNET_asprintf (&ret, - "(%s|%s%s)", - middle, - afterp, dots); - else - GNUNET_asprintf (&ret, - "%s%s", - afterp, dots); - } - else - { - if (strlen (middle) > 0) - GNUNET_asprintf (&ret, - "%s|%s", - middle, - after); - else - GNUNET_asprintf (&ret, - "%s", - after); - } - } - else if (strlen (middle) > 0) - { - GNUNET_asprintf (&ret, - "%s", - middle); - } - else - { - ret = GNUNET_strdup (""); - } - GNUNET_free (middle); - GNUNET_free (reclp); - GNUNET_free (rechp); - GNUNET_free (recl); - GNUNET_free (rech); - return ret; -} - - -/** - * Convert a port policy to a regular expression. Note: this is a - * very simplistic implementation, we might want to consider doing - * something more sophisiticated (resulting in smaller regular - * expressions) at a later time. - * - * @param pp port policy to convert - * @return NULL on error - */ -static char * -port_to_regex (const struct GNUNET_STRINGS_PortPolicy *pp) -{ - char *reg; - char *ret; - char *pos; - unsigned int i; - unsigned int cnt; - - if ( (0 == pp->start_port) || - ( (1 == pp->start_port) && - (0xFFFF == pp->end_port) && - (GNUNET_NO == pp->negate_portrange)) ) - return GNUNET_strdup (DOT DOT DOT DOT); - if ( (pp->start_port == pp->end_port) && - (GNUNET_NO == pp->negate_portrange)) - { - GNUNET_asprintf (&ret, - "%04X", - pp->start_port); - return ret; - } - if (pp->end_port < pp->start_port) - return NULL; - - if (GNUNET_YES == pp->negate_portrange) - { - ret = compute_policy (0, 0xFFFF, 0x1000, pp); - } - else - { - cnt = pp->end_port - pp->start_port + 1; - reg = GNUNET_malloc (cnt * 5 + 1); - pos = reg; - for (i=1;i<=0xFFFF;i++) - { - if ( (i >= pp->start_port) && (i <= pp->end_port) ) - { - if (pos == reg) - { - GNUNET_snprintf (pos, - 5, - "%04X", - i); - } - else - { - GNUNET_snprintf (pos, - 6, - "|%04X", - i); - } - pos += strlen (pos); - } - } - GNUNET_asprintf (&ret, - "(%s)", - reg); - GNUNET_free (reg); - } - return ret; -} - - -/** - * Convert an address (IPv4 or IPv6) to a regex. - * - * @param addr address - * @param mask network mask - * @param len number of bytes in @a addr and @a mask - * @return NULL on error, otherwise regex for the address - */ -static char * -address_to_regex (const void *addr, - const void *mask, - size_t len) -{ - const uint16_t *a = addr; - const uint16_t *m = mask; - char *ret; - char *tmp; - char *reg; - unsigned int i; - - ret = NULL; - GNUNET_assert (1 != (len % 2)); - for (i=0;inetwork, - &v4->netmask, - sizeof (struct in_addr)); - if (NULL == reg) - return NULL; - pp = port_to_regex (&v4->pp); - if (NULL == pp) - { - GNUNET_free (reg); - return NULL; - } - GNUNET_asprintf (&ret, - "4-%s-%s", - pp, reg); - GNUNET_free (pp); - GNUNET_free (reg); - return ret; -} - - -/** - * Convert a single line of an IPv4 policy to a regular expression. - * - * @param v6 line to convert - * @return NULL on error - */ -static char * -ipv6_to_regex (const struct GNUNET_STRINGS_IPv6NetworkPolicy *v6) -{ - char *reg; - char *pp; - char *ret; - - reg = address_to_regex (&v6->network, - &v6->netmask, - sizeof (struct in6_addr)); - if (NULL == reg) - return NULL; - pp = port_to_regex (&v6->pp); - if (NULL == pp) - { - GNUNET_free (reg); - return NULL; - } - GNUNET_asprintf (&ret, - "6-%s-%s", - pp, reg); - GNUNET_free (pp); - GNUNET_free (reg); - return ret; -} - - -/** - * Convert an exit policy to a regular expression. The exit policy - * specifies a set of subnets this peer is willing to serve as an - * exit for; the resulting regular expression will match the - * IPv4 address strings as returned by #GNUNET_TUN_ipv4toregexsearch(). - * - * @param policy exit policy specification - * @return regular expression, NULL on error - */ -char * -GNUNET_TUN_ipv4policy2regex (const char *policy) -{ - struct GNUNET_STRINGS_IPv4NetworkPolicy *np; - char *reg; - char *tmp; - char *line; - unsigned int i; - - np = GNUNET_STRINGS_parse_ipv4_policy (policy); - if (NULL == np) - return NULL; - reg = NULL; - for (i=0; (0 == i) || (0 != np[i].network.s_addr); i++) - { - line = ipv4_to_regex (&np[i]); - if (NULL == line) - { - GNUNET_free_non_null (reg); - GNUNET_free (np); - return NULL; - } - if (NULL == reg) - { - reg = line; - } - else - { - GNUNET_asprintf (&tmp, - "%s|(%s)", - reg, line); - GNUNET_free (reg); - GNUNET_free (line); - reg = tmp; - } - if (0 == np[i].network.s_addr) - break; - } - GNUNET_free (np); - return reg; -} - - -/** - * Convert an exit policy to a regular expression. The exit policy - * specifies a set of subnets this peer is willing to serve as an - * exit for; the resulting regular expression will match the - * IPv6 address strings as returned by #GNUNET_TUN_ipv6toregexsearch(). - * - * @param policy exit policy specification - * @return regular expression, NULL on error - */ -char * -GNUNET_TUN_ipv6policy2regex (const char *policy) -{ - struct in6_addr zero; - struct GNUNET_STRINGS_IPv6NetworkPolicy *np; - char *reg; - char *tmp; - char *line; - unsigned int i; - - np = GNUNET_STRINGS_parse_ipv6_policy (policy); - if (NULL == np) - return NULL; - reg = NULL; - memset (&zero, 0, sizeof (struct in6_addr)); - for (i=0; (0 == i) || (0 != memcmp (&zero, &np[i].network, sizeof (struct in6_addr))); i++) - { - line = ipv6_to_regex (&np[i]); - if (NULL == line) - { - GNUNET_free_non_null (reg); - GNUNET_free (np); - return NULL; - } - if (NULL == reg) - { - reg = line; - } - else - { - GNUNET_asprintf (&tmp, - "%s|(%s)", - reg, line); - GNUNET_free (reg); - GNUNET_free (line); - reg = tmp; - } - if (0 == memcmp (&zero, &np[i].network, sizeof (struct in6_addr))) - break; - } - GNUNET_free (np); - return reg; -} - - -/** - * Hash the service name of a hosted service to the - * hash code that is used to identify the service on - * the network. - * - * @param service_name a string - * @param hc corresponding hash - */ -void -GNUNET_TUN_service_name_to_hash (const char *service_name, - struct GNUNET_HashCode *hc) -{ - GNUNET_CRYPTO_hash (service_name, - strlen (service_name), - hc); -} - - -/** - * Compute the CADET port given a service descriptor - * (returned from #GNUNET_TUN_service_name_to_hash) and - * a TCP/UDP port @a ip_port. - * - * @param desc service shared secret - * @param ip_port TCP/UDP port, use 0 for ICMP - * @param[out] cadet_port CADET port to use - */ -void -GNUNET_TUN_compute_service_cadet_port (const struct GNUNET_HashCode *desc, - uint16_t ip_port, - struct GNUNET_HashCode *cadet_port) -{ - uint16_t be_port = htons (ip_port); - - *cadet_port = *desc; - GNUNET_memcpy (cadet_port, - &be_port, - sizeof (uint16_t)); -} - - -/* end of regex.c */ diff --git a/src/tun/test_regex.c b/src/tun/test_regex.c deleted file mode 100644 index 2e7d52828..000000000 --- a/src/tun/test_regex.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2012, 2013 GNUnet e.V. - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ -/** - * @file tun/test_regex.c - * @brief simple test for regex.c iptoregex functions - * @author Maximilian Szengel - */ -#include "platform.h" -#include "gnunet_tun_lib.h" - -/** - * 'wildcard', matches all possible values (for HEX encoding). - */ -#define DOT "(0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)" - - -static int -test_iptoregex (const char *ipv4, - uint16_t port, - const char *expectedv4, - const char *ipv6, - uint16_t port6, - const char *expectedv6) -{ - int error = 0; - - struct in_addr a; - struct in6_addr b; - char rxv4[GNUNET_TUN_IPV4_REGEXLEN]; - char rxv6[GNUNET_TUN_IPV6_REGEXLEN]; - - GNUNET_assert (1 == inet_pton (AF_INET, ipv4, &a)); - GNUNET_TUN_ipv4toregexsearch (&a, port, rxv4); - - if (0 != strcmp (rxv4, expectedv4)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected: %s but got: %s\n", - expectedv4, - rxv4); - error++; - } - - GNUNET_assert (1 == inet_pton (AF_INET6, ipv6, &b)); - GNUNET_TUN_ipv6toregexsearch (&b, port6, rxv6); - if (0 != strcmp (rxv6, expectedv6)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected: %s but got: %s\n", - expectedv6, rxv6); - error++; - } - return error; -} - - -static int -test_policy4toregex (const char *policy, - const char *regex) -{ - char *r; - int ret; - - ret = 0; - r = GNUNET_TUN_ipv4policy2regex (policy); - if (NULL == r) - { - GNUNET_break (0); - return 1; - } - if (0 != strcmp (regex, r)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected: `%s' but got: `%s'\n", - regex, r); - ret = 2; - } - GNUNET_free (r); - return ret; -} - - -static int -test_policy6toregex (const char *policy, - const char *regex) -{ - char *r; - int ret; - - ret = 0; - r = GNUNET_TUN_ipv6policy2regex (policy); - if (NULL == r) - { - GNUNET_break (0); - return 1; - } - if (0 != strcmp (regex, r)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected: `%s' but got: `%s'\n", - regex, r); - ret = 2; - } - GNUNET_free (r); - return ret; -} - - -int -main (int argc, char *argv[]) -{ - int error; - char *r; - - GNUNET_log_setup ("test-regex", "WARNING", NULL); - error = 0; - - /* this is just a performance test ... */ - r = GNUNET_TUN_ipv4policy2regex ("1.2.3.4/16:!25;"); - GNUNET_break (NULL != r); - GNUNET_free (r); - - error += - test_iptoregex ("192.1.2.3", 2086, - "4-0826-C0010203", - "FFFF::1", 8080, - "6-1F90-FFFF0000000000000000000000000001"); - error += - test_iptoregex ("187.238.255.0", 80, - "4-0050-BBEEFF00", - "E1E1:73F9:51BE::0", 49, - "6-0031-E1E173F951BE00000000000000000000"); - error += - test_policy4toregex ("192.1.2.0/24:80;", - "4-0050-C00102" DOT DOT); - error += - test_policy4toregex ("192.1.0.0/16;", - "4-" DOT DOT DOT DOT "-C001" DOT DOT DOT DOT); - error += - test_policy4toregex ("192.1.0.0/16:80-81;", - "4-(0050|0051)-C001" DOT DOT DOT DOT); - error += - test_policy4toregex ("192.1.0.0/8:!3-65535;", - "4-000(0|1|2)-C0" DOT DOT DOT DOT DOT DOT); - error += - test_policy4toregex ("192.1.0.0/8:!25-56;", - "4-(0(0(0"DOT"|1(0|1|2|3|4|5|6|7|8)|3(9|A|B|C|D|E|F)|(4|5|6|7|8|9|A|B|C|D|E|F)"DOT")|(1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"DOT DOT")|(1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"DOT DOT DOT")-C0"DOT DOT DOT DOT DOT DOT); - error += - test_policy6toregex ("E1E1::1;", - "6-"DOT DOT DOT DOT"-E1E10000000000000000000000000001"); - error += - test_policy6toregex ("E1E1:ABCD::1/120;", - "6-"DOT DOT DOT DOT"-E1E1ABCD0000000000000000000000" DOT DOT); - error += - test_policy6toregex ("E1E1:ABCD::ABCD/126;", - "6-"DOT DOT DOT DOT"-E1E1ABCD00000000000000000000ABC(C|D|E|F)"); - error += - test_policy6toregex ("E1E1:ABCD::ABCD/127;", - "6-"DOT DOT DOT DOT"-E1E1ABCD00000000000000000000ABC(C|D)"); - error += - test_policy6toregex ("E1E1:ABCD::ABCD/128:80;", - "6-0050-E1E1ABCD00000000000000000000ABCD"); - return error; -} diff --git a/src/tun/test_tun.c b/src/tun/test_tun.c deleted file mode 100644 index edbd4c05d..000000000 --- a/src/tun/test_tun.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2010, 2011, 2012 Christian Grothoff - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -/** - * @file tun/test_tun.c - * @brief test for tun.c - * @author Christian Grothoff - */ -#include "platform.h" -#include "gnunet_tun_lib.h" - -static int ret; - -static void -test_udp (size_t pll, - int pl_fill, - uint16_t crc) -{ - struct GNUNET_TUN_IPv4Header ip; - struct GNUNET_TUN_UdpHeader udp; - char payload[pll]; - struct in_addr src; - struct in_addr dst; - - GNUNET_assert (1 == inet_pton (AF_INET, "1.2.3.4", &src)); - GNUNET_assert (1 == inet_pton (AF_INET, "122.2.3.5", &dst)); - memset (payload, pl_fill, sizeof (payload)); - GNUNET_TUN_initialize_ipv4_header (&ip, - IPPROTO_UDP, - pll + sizeof (udp), - &src, - &dst); - udp.source_port = htons (4242); - udp.destination_port = htons (4242); - udp.len = htons (pll); - GNUNET_TUN_calculate_udp4_checksum (&ip, - &udp, - payload, - pll); - if (crc != ntohs (udp.crc)) - { - fprintf (stderr, "Got CRC: %u, wanted: %u\n", - ntohs (udp.crc), - crc); - ret = 1; - } -} - -int main (int argc, - char **argv) -{ - test_udp (4, 3, 22439); - test_udp (4, 1, 23467); - test_udp (7, 17, 6516); - test_udp (12451, 251, 42771); - return ret; -} diff --git a/src/tun/tun.c b/src/tun/tun.c deleted file mode 100644 index f85f72209..000000000 --- a/src/tun/tun.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2010, 2011, 2012 Christian Grothoff - - GNUnet is free software: you can redistribute it and/or modify it - under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, - or (at your option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ - -/** - * @file tun/tun.c - * @brief standard IP calculations for TUN interaction - * @author Philipp Toelke - * @author Christian Grothoff - */ -#include "platform.h" -#include "gnunet_tun_lib.h" - -/** - * IP TTL we use for packets that we assemble (8 bit unsigned integer) - */ -#define FRESH_TTL 64 - - -/** - * Initialize an IPv4 header. - * - * @param ip header to initialize - * @param protocol protocol to use (i.e. IPPROTO_UDP) - * @param payload_length number of bytes of payload that follow (excluding IPv4 header) - * @param src source IP address to use - * @param dst destination IP address to use - */ -void -GNUNET_TUN_initialize_ipv4_header (struct GNUNET_TUN_IPv4Header *ip, - uint8_t protocol, - uint16_t payload_length, - const struct in_addr *src, - const struct in_addr *dst) -{ - GNUNET_assert (20 == sizeof (struct GNUNET_TUN_IPv4Header)); - GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv4Header)); - memset (ip, 0, sizeof (struct GNUNET_TUN_IPv4Header)); - ip->header_length = sizeof (struct GNUNET_TUN_IPv4Header) / 4; - ip->version = 4; - ip->total_length = htons (sizeof (struct GNUNET_TUN_IPv4Header) + payload_length); - ip->identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, - 65536); - ip->ttl = FRESH_TTL; - ip->protocol = protocol; - ip->source_address = *src; - ip->destination_address = *dst; - ip->checksum = GNUNET_CRYPTO_crc16_n (ip, sizeof (struct GNUNET_TUN_IPv4Header)); -} - - -/** - * Initialize an IPv6 header. - * - * @param ip header to initialize - * @param protocol protocol to use (i.e. IPPROTO_UDP), technically "next_header" for IPv6 - * @param payload_length number of bytes of payload that follow (excluding IPv6 header) - * @param src source IP address to use - * @param dst destination IP address to use - */ -void -GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip, - uint8_t protocol, - uint16_t payload_length, - const struct in6_addr *src, - const struct in6_addr *dst) -{ - GNUNET_assert (40 == sizeof (struct GNUNET_TUN_IPv6Header)); - GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv6Header)); - memset (ip, 0, sizeof (struct GNUNET_TUN_IPv6Header)); - ip->version = 6; - ip->next_header = protocol; - ip->payload_length = htons ((uint16_t) payload_length); - ip->hop_limit = FRESH_TTL; - ip->destination_address = *dst; - ip->source_address = *src; -} - - -/** - * Calculate IPv4 TCP checksum. - * - * @param ip ipv4 header fully initialized - * @param tcp TCP header (initialized except for CRC) - * @param payload the TCP payload - * @param payload_length number of bytes of TCP payload - */ -void -GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, - struct GNUNET_TUN_TcpHeader *tcp, - const void *payload, - uint16_t payload_length) -{ - uint32_t sum; - uint16_t tmp; - - GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader)); - GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_TcpHeader) == - ntohs (ip->total_length)); - GNUNET_assert (IPPROTO_TCP == ip->protocol); - - tcp->crc = 0; - sum = GNUNET_CRYPTO_crc16_step (0, - &ip->source_address, - sizeof (struct in_addr) * 2); - tmp = htons (IPPROTO_TCP); - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t)); - tmp = htons (payload_length + sizeof (struct GNUNET_TUN_TcpHeader)); - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t)); - sum = GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof (struct GNUNET_TUN_TcpHeader)); - sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); - tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); -} - - -/** - * Calculate IPv6 TCP checksum. - * - * @param ip ipv6 header fully initialized - * @param tcp header (initialized except for CRC) - * @param payload the TCP payload - * @param payload_length number of bytes of TCP payload - */ -void -GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, - struct GNUNET_TUN_TcpHeader *tcp, - const void *payload, - uint16_t payload_length) -{ - uint32_t sum; - uint32_t tmp; - - GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader)); - GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_TcpHeader) == - ntohs (ip->payload_length)); - GNUNET_assert (IPPROTO_TCP == ip->next_header); - tcp->crc = 0; - sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, 2 * sizeof (struct in6_addr)); - tmp = htonl (sizeof (struct GNUNET_TUN_TcpHeader) + payload_length); - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); - tmp = htonl (IPPROTO_TCP); - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); - sum = GNUNET_CRYPTO_crc16_step (sum, tcp, - sizeof (struct GNUNET_TUN_TcpHeader)); - sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); - tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); -} - - -/** - * Calculate IPv4 UDP checksum. - * - * @param ip ipv4 header fully initialized - * @param udp UDP header (initialized except for CRC) - * @param payload the UDP payload - * @param payload_length number of bytes of UDP payload - */ -void -GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, - struct GNUNET_TUN_UdpHeader *udp, - const void *payload, - uint16_t payload_length) -{ - uint32_t sum; - uint16_t tmp; - - GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); - GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_UdpHeader) == - ntohs (ip->total_length)); - GNUNET_assert (IPPROTO_UDP == ip->protocol); - - udp->crc = 0; /* technically optional, but we calculate it anyway, just to be sure */ - sum = GNUNET_CRYPTO_crc16_step (0, - &ip->source_address, - sizeof (struct in_addr) * 2); - tmp = htons (IPPROTO_UDP); - sum = GNUNET_CRYPTO_crc16_step (sum, - &tmp, - sizeof (uint16_t)); - tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); - sum = GNUNET_CRYPTO_crc16_step (sum, - &tmp, - sizeof (uint16_t)); - sum = GNUNET_CRYPTO_crc16_step (sum, - udp, - sizeof (struct GNUNET_TUN_UdpHeader)); - sum = GNUNET_CRYPTO_crc16_step (sum, - payload, - payload_length); - udp->crc = GNUNET_CRYPTO_crc16_finish (sum); -} - - -/** - * Calculate IPv6 UDP checksum. - * - * @param ip ipv6 header fully initialized - * @param udp UDP header (initialized except for CRC) - * @param payload the UDP payload - * @param payload_length number of bytes of UDP payload - */ -void -GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, - struct GNUNET_TUN_UdpHeader *udp, - const void *payload, - uint16_t payload_length) -{ - uint32_t sum; - uint32_t tmp; - - GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) == - ntohs (ip->payload_length)); - GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) == - ntohs (udp->len)); - GNUNET_assert (IPPROTO_UDP == ip->next_header); - - udp->crc = 0; - sum = GNUNET_CRYPTO_crc16_step (0, - &ip->source_address, - sizeof (struct in6_addr) * 2); - tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); /* aka udp->len */ - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); - tmp = htons (ip->next_header); - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); - sum = GNUNET_CRYPTO_crc16_step (sum, udp, sizeof (struct GNUNET_TUN_UdpHeader)); - sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); - udp->crc = GNUNET_CRYPTO_crc16_finish (sum); -} - - -/** - * Calculate ICMP checksum. - * - * @param icmp IMCP header (initialized except for CRC) - * @param payload the ICMP payload - * @param payload_length number of bytes of ICMP payload - */ -void -GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp, - const void *payload, - uint16_t payload_length) -{ - uint32_t sum; - - GNUNET_assert (8 == sizeof (struct GNUNET_TUN_IcmpHeader)); - icmp->crc = 0; - sum = GNUNET_CRYPTO_crc16_step (0, - icmp, - sizeof (struct GNUNET_TUN_IcmpHeader)); - sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); - icmp->crc = GNUNET_CRYPTO_crc16_finish (sum); -} - - -/** - * Check if two sockaddrs are equal. - * - * @param sa one address - * @param sb another address - * @param include_port also check ports - * @return #GNUNET_YES if they are equal - */ -int -GNUNET_TUN_sockaddr_cmp (const struct sockaddr *sa, - const struct sockaddr *sb, - int include_port) -{ - if (sa->sa_family != sb->sa_family) - return GNUNET_NO; - - switch (sa->sa_family) - { - case AF_INET: - { - const struct sockaddr_in *sa4 = (const struct sockaddr_in *) sa; - const struct sockaddr_in *sb4 = (const struct sockaddr_in *) sb; - return (sa4->sin_addr.s_addr == sb4->sin_addr.s_addr); - } - case AF_INET6: - { - const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *) sa; - const struct sockaddr_in6 *sb6 = (const struct sockaddr_in6 *) sb; - - return (0 == memcmp(&sa6->sin6_addr, - &sb6->sin6_addr, - sizeof (struct in6_addr))); - } - default: - GNUNET_break (0); - return GNUNET_SYSERR; - } -} - - -/* end of tun.c */ diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 4296199db..ec7bcb016 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -89,6 +89,8 @@ libgnunetutil_la_SOURCES = \ crypto_rsa.c \ disk.c \ disk.h \ + dnsparser.c \ + dnsstub.c \ getopt.c \ getopt_helpers.c \ helper.c \ @@ -104,12 +106,14 @@ libgnunetutil_la_SOURCES = \ peer.c \ plugin.c \ program.c \ + regex.c \ resolver_api.c resolver.h \ scheduler.c \ service.c \ signal.c \ strings.c \ time.c \ + tun.c \ speedup.c speedup.h libgnunetutil_la_LIBADD = \ @@ -117,7 +121,7 @@ libgnunetutil_la_LIBADD = \ $(LIBGCRYPT_LIBS) \ $(LTLIBICONV) \ $(LTLIBINTL) \ - -lltdl $(Z_LIBS) -lunistring $(XLIB) + -lltdl -lidn $(Z_LIBS) -lunistring $(XLIB) libgnunetutil_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ @@ -291,19 +295,22 @@ check_PROGRAMS = \ test_crypto_rsa \ test_disk \ test_getopt \ + test_hexcoder \ test_mq \ test_os_network \ test_peer \ test_plugin \ test_program \ + test_regex \ test_resolver_api.nc \ test_scheduler \ test_scheduler_delay \ test_service \ test_strings \ test_strings_to_data \ - test_time \ test_speedup \ + test_time \ + test_tun \ $(BENCHMARKS) \ test_os_start_process \ test_common_logging_runtime_loglevels @@ -319,6 +326,20 @@ test_bio_SOURCES = \ test_bio_LDADD = \ libgnunetutil.la +test_hexcoder_SOURCES = \ + test_hexcoder.c +test_hexcoder_LDADD = \ + libgnunetutil.la + +test_tun_SOURCES = \ + test_tun.c +test_tun_LDADD = \ + libgnunetutil.la + +test_regex_SOURCES = \ + test_regex.c +test_regex_LDADD = \ + libgnunetutil.la test_os_start_process_SOURCES = \ test_os_start_process.c diff --git a/src/util/dnsparser.c b/src/util/dnsparser.c new file mode 100644 index 000000000..32ad7c0c2 --- /dev/null +++ b/src/util/dnsparser.c @@ -0,0 +1,1334 @@ +/* + This file is part of GNUnet + Copyright (C) 2010-2014 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +/** + * @file dns/dnsparser.c + * @brief helper library to parse DNS packets. + * @author Philipp Toelke + * @author Christian Grothoff + */ +#include "platform.h" +#include +#if WINDOWS +#include +#endif +#include "gnunet_util_lib.h" +#include "gnunet_dnsparser_lib.h" +#include "gnunet_tun_lib.h" + + +/** + * Check if a label in UTF-8 format can be coded into valid IDNA. + * This can fail if the ASCII-conversion becomes longer than 63 characters. + * + * @param label label to check (UTF-8 string) + * @return #GNUNET_OK if the label can be converted to IDNA, + * #GNUNET_SYSERR if the label is not valid for DNS names + */ +int +GNUNET_DNSPARSER_check_label (const char *label) +{ + char *output; + size_t slen; + + if (NULL != strchr (label, '.')) + return GNUNET_SYSERR; /* not a label! Did you mean GNUNET_DNSPARSER_check_name? */ + if (IDNA_SUCCESS != + idna_to_ascii_8z (label, &output, IDNA_ALLOW_UNASSIGNED)) + return GNUNET_SYSERR; + slen = strlen (output); +#if WINDOWS + idn_free (output); +#else + free (output); +#endif + return (slen > 63) ? GNUNET_SYSERR : GNUNET_OK; +} + + +/** + * Check if a label in UTF-8 format can be coded into valid IDNA. + * This can fail if the ASCII-conversion becomes longer than 253 characters. + * + * @param name name to check (UTF-8 string) + * @return #GNUNET_OK if the label can be converted to IDNA, + * #GNUNET_SYSERR if the label is not valid for DNS names + */ +int +GNUNET_DNSPARSER_check_name (const char *name) +{ + char *ldup; + char *output; + size_t slen; + char *tok; + + ldup = GNUNET_strdup (name); + for (tok = strtok (ldup, "."); NULL != tok; tok = strtok (NULL, ".")) + if (GNUNET_OK != + GNUNET_DNSPARSER_check_label (tok)) + { + GNUNET_free (ldup); + return GNUNET_SYSERR; + } + GNUNET_free (ldup); + if (IDNA_SUCCESS != + idna_to_ascii_8z (name, &output, IDNA_ALLOW_UNASSIGNED)) + return GNUNET_SYSERR; + slen = strlen (output); +#if WINDOWS + idn_free (output); +#else + free (output); +#endif + return (slen > 253) ? GNUNET_SYSERR : GNUNET_OK; +} + + +/** + * Free SOA information record. + * + * @param soa record to free + */ +void +GNUNET_DNSPARSER_free_soa (struct GNUNET_DNSPARSER_SoaRecord *soa) +{ + if (NULL == soa) + return; + GNUNET_free_non_null (soa->mname); + GNUNET_free_non_null (soa->rname); + GNUNET_free (soa); +} + + +/** + * Free CERT information record. + * + * @param cert record to free + */ +void +GNUNET_DNSPARSER_free_cert (struct GNUNET_DNSPARSER_CertRecord *cert) +{ + if (NULL == cert) + return; + GNUNET_free_non_null (cert->certificate_data); + GNUNET_free (cert); +} + + +/** + * Free SRV information record. + * + * @param srv record to free + */ +void +GNUNET_DNSPARSER_free_srv (struct GNUNET_DNSPARSER_SrvRecord *srv) +{ + if (NULL == srv) + return; + GNUNET_free_non_null (srv->target); + GNUNET_free (srv); +} + + +/** + * Free MX information record. + * + * @param mx record to free + */ +void +GNUNET_DNSPARSER_free_mx (struct GNUNET_DNSPARSER_MxRecord *mx) +{ + if (NULL == mx) + return; + GNUNET_free_non_null (mx->mxhost); + GNUNET_free (mx); +} + + +/** + * Free the given DNS record. + * + * @param r record to free + */ +void +GNUNET_DNSPARSER_free_record (struct GNUNET_DNSPARSER_Record *r) +{ + GNUNET_free_non_null (r->name); + switch (r->type) + { + case GNUNET_DNSPARSER_TYPE_MX: + GNUNET_DNSPARSER_free_mx (r->data.mx); + break; + case GNUNET_DNSPARSER_TYPE_SOA: + GNUNET_DNSPARSER_free_soa (r->data.soa); + break; + case GNUNET_DNSPARSER_TYPE_SRV: + GNUNET_DNSPARSER_free_srv (r->data.srv); + break; + case GNUNET_DNSPARSER_TYPE_CERT: + GNUNET_DNSPARSER_free_cert (r->data.cert); + break; + case GNUNET_DNSPARSER_TYPE_NS: + case GNUNET_DNSPARSER_TYPE_CNAME: + case GNUNET_DNSPARSER_TYPE_PTR: + GNUNET_free_non_null (r->data.hostname); + break; + default: + GNUNET_free_non_null (r->data.raw.data); + break; + } +} + + +/** + * Parse name inside of a DNS query or record. + * + * @param udp_payload entire UDP payload + * @param udp_payload_length length of @a udp_payload + * @param off pointer to the offset of the name to parse in the udp_payload (to be + * incremented by the size of the name) + * @param depth current depth of our recursion (to prevent stack overflow) + * @return name as 0-terminated C string on success, NULL if the payload is malformed + */ +static char * +parse_name (const char *udp_payload, + size_t udp_payload_length, + size_t *off, + unsigned int depth) +{ + const uint8_t *input = (const uint8_t *) udp_payload; + char *ret; + char *tmp; + char *xstr; + uint8_t len; + size_t xoff; + char *utf8; + Idna_rc rc; + + ret = GNUNET_strdup (""); + while (1) + { + if (*off >= udp_payload_length) + { + GNUNET_break_op (0); + goto error; + } + len = input[*off]; + if (0 == len) + { + (*off)++; + break; + } + if (len < 64) + { + if (*off + 1 + len > udp_payload_length) + { + GNUNET_break_op (0); + goto error; + } + GNUNET_asprintf (&tmp, + "%.*s", + (int) len, + &udp_payload[*off + 1]); + if (IDNA_SUCCESS != + (rc = idna_to_unicode_8z8z (tmp, &utf8, IDNA_ALLOW_UNASSIGNED))) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Failed to convert DNS IDNA name `%s' to UTF-8: %s\n"), + tmp, + idna_strerror (rc)); + GNUNET_free (tmp); + GNUNET_asprintf (&tmp, + "%s%.*s.", + ret, + (int) len, + &udp_payload[*off + 1]); + } + else + { + GNUNET_free (tmp); + GNUNET_asprintf (&tmp, + "%s%s.", + ret, + utf8); +#if WINDOWS + idn_free (utf8); +#else + free (utf8); +#endif + } + GNUNET_free (ret); + ret = tmp; + *off += 1 + len; + } + else if ((64 | 128) == (len & (64 | 128)) ) + { + if (depth > 32) + { + GNUNET_break_op (0); + goto error; /* hard bound on stack to prevent "infinite" recursion, disallow! */ + } + /* pointer to string */ + if (*off + 1 > udp_payload_length) + { + GNUNET_break_op (0); + goto error; + } + xoff = ((len - (64 | 128)) << 8) + input[*off+1]; + xstr = parse_name (udp_payload, + udp_payload_length, + &xoff, + depth + 1); + if (NULL == xstr) + { + GNUNET_break_op (0); + goto error; + } + GNUNET_asprintf (&tmp, + "%s%s.", + ret, + xstr); + GNUNET_free (ret); + GNUNET_free (xstr); + ret = tmp; + if (strlen (ret) > udp_payload_length) + { + GNUNET_break_op (0); + goto error; /* we are looping (building an infinite string) */ + } + *off += 2; + /* pointers always terminate names */ + break; + } + else + { + /* neither pointer nor inline string, not supported... */ + GNUNET_break_op (0); + goto error; + } + } + if (0 < strlen(ret)) + ret[strlen(ret)-1] = '\0'; /* eat tailing '.' */ + return ret; + error: + GNUNET_break_op (0); + GNUNET_free (ret); + return NULL; +} + + +/** + * Parse name inside of a DNS query or record. + * + * @param udp_payload entire UDP payload + * @param udp_payload_length length of @a udp_payload + * @param off pointer to the offset of the name to parse in the udp_payload (to be + * incremented by the size of the name) + * @return name as 0-terminated C string on success, NULL if the payload is malformed + */ +char * +GNUNET_DNSPARSER_parse_name (const char *udp_payload, + size_t udp_payload_length, + size_t *off) +{ + return parse_name (udp_payload, udp_payload_length, off, 0); +} + + +/** + * Parse a DNS query entry. + * + * @param udp_payload entire UDP payload + * @param udp_payload_length length of @a udp_payload + * @param off pointer to the offset of the query to parse in the udp_payload (to be + * incremented by the size of the query) + * @param q where to write the query information + * @return #GNUNET_OK on success, #GNUNET_SYSERR if the query is malformed + */ +int +GNUNET_DNSPARSER_parse_query (const char *udp_payload, + size_t udp_payload_length, + size_t *off, + struct GNUNET_DNSPARSER_Query *q) +{ + char *name; + struct GNUNET_TUN_DnsQueryLine ql; + + name = GNUNET_DNSPARSER_parse_name (udp_payload, + udp_payload_length, + off); + if (NULL == name) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + q->name = name; + if (*off + sizeof (struct GNUNET_TUN_DnsQueryLine) > udp_payload_length) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_memcpy (&ql, &udp_payload[*off], sizeof (ql)); + *off += sizeof (ql); + q->type = ntohs (ql.type); + q->dns_traffic_class = ntohs (ql.dns_traffic_class); + return GNUNET_OK; +} + + +/** + * Parse a DNS SOA record. + * + * @param udp_payload reference to UDP packet + * @param udp_payload_length length of @a udp_payload + * @param off pointer to the offset of the query to parse in the SOA record (to be + * incremented by the size of the record), unchanged on error + * @return the parsed SOA record, NULL on error + */ +struct GNUNET_DNSPARSER_SoaRecord * +GNUNET_DNSPARSER_parse_soa (const char *udp_payload, + size_t udp_payload_length, + size_t *off) +{ + struct GNUNET_DNSPARSER_SoaRecord *soa; + struct GNUNET_TUN_DnsSoaRecord soa_bin; + size_t old_off; + + old_off = *off; + soa = GNUNET_new (struct GNUNET_DNSPARSER_SoaRecord); + soa->mname = GNUNET_DNSPARSER_parse_name (udp_payload, + udp_payload_length, + off); + soa->rname = GNUNET_DNSPARSER_parse_name (udp_payload, + udp_payload_length, + off); + if ( (NULL == soa->mname) || + (NULL == soa->rname) || + (*off + sizeof (struct GNUNET_TUN_DnsSoaRecord) > udp_payload_length) ) + { + GNUNET_break_op (0); + GNUNET_DNSPARSER_free_soa (soa); + *off = old_off; + return NULL; + } + GNUNET_memcpy (&soa_bin, + &udp_payload[*off], + sizeof (struct GNUNET_TUN_DnsSoaRecord)); + soa->serial = ntohl (soa_bin.serial); + soa->refresh = ntohl (soa_bin.refresh); + soa->retry = ntohl (soa_bin.retry); + soa->expire = ntohl (soa_bin.expire); + soa->minimum_ttl = ntohl (soa_bin.minimum); + (*off) += sizeof (struct GNUNET_TUN_DnsSoaRecord); + return soa; +} + + +/** + * Parse a DNS MX record. + * + * @param udp_payload reference to UDP packet + * @param udp_payload_length length of @a udp_payload + * @param off pointer to the offset of the query to parse in the MX record (to be + * incremented by the size of the record), unchanged on error + * @return the parsed MX record, NULL on error + */ +struct GNUNET_DNSPARSER_MxRecord * +GNUNET_DNSPARSER_parse_mx (const char *udp_payload, + size_t udp_payload_length, + size_t *off) +{ + struct GNUNET_DNSPARSER_MxRecord *mx; + uint16_t mxpref; + size_t old_off; + + old_off = *off; + if (*off + sizeof (uint16_t) > udp_payload_length) + { + GNUNET_break_op (0); + return NULL; + } + GNUNET_memcpy (&mxpref, &udp_payload[*off], sizeof (uint16_t)); + (*off) += sizeof (uint16_t); + mx = GNUNET_new (struct GNUNET_DNSPARSER_MxRecord); + mx->preference = ntohs (mxpref); + mx->mxhost = GNUNET_DNSPARSER_parse_name (udp_payload, + udp_payload_length, + off); + if (NULL == mx->mxhost) + { + GNUNET_break_op (0); + GNUNET_DNSPARSER_free_mx (mx); + *off = old_off; + return NULL; + } + return mx; +} + + +/** + * Parse a DNS SRV record. + * + * @param udp_payload reference to UDP packet + * @param udp_payload_length length of @a udp_payload + * @param off pointer to the offset of the query to parse in the SRV record (to be + * incremented by the size of the record), unchanged on error + * @return the parsed SRV record, NULL on error + */ +struct GNUNET_DNSPARSER_SrvRecord * +GNUNET_DNSPARSER_parse_srv (const char *udp_payload, + size_t udp_payload_length, + size_t *off) +{ + struct GNUNET_DNSPARSER_SrvRecord *srv; + struct GNUNET_TUN_DnsSrvRecord srv_bin; + size_t old_off; + + old_off = *off; + if (*off + sizeof (struct GNUNET_TUN_DnsSrvRecord) > udp_payload_length) + return NULL; + GNUNET_memcpy (&srv_bin, + &udp_payload[*off], + sizeof (struct GNUNET_TUN_DnsSrvRecord)); + (*off) += sizeof (struct GNUNET_TUN_DnsSrvRecord); + srv = GNUNET_new (struct GNUNET_DNSPARSER_SrvRecord); + srv->priority = ntohs (srv_bin.prio); + srv->weight = ntohs (srv_bin.weight); + srv->port = ntohs (srv_bin.port); + srv->target = GNUNET_DNSPARSER_parse_name (udp_payload, + udp_payload_length, + off); + if (NULL == srv->target) + { + GNUNET_DNSPARSER_free_srv (srv); + *off = old_off; + return NULL; + } + return srv; +} + + +/** + * Parse a DNS CERT record. + * + * @param udp_payload reference to UDP packet + * @param udp_payload_length length of @a udp_payload + * @param off pointer to the offset of the query to parse in the CERT record (to be + * incremented by the size of the record), unchanged on error + * @return the parsed CERT record, NULL on error + */ +struct GNUNET_DNSPARSER_CertRecord * +GNUNET_DNSPARSER_parse_cert (const char *udp_payload, + size_t udp_payload_length, + size_t *off) +{ + struct GNUNET_DNSPARSER_CertRecord *cert; + struct GNUNET_TUN_DnsCertRecord dcert; + + if (*off + sizeof (struct GNUNET_TUN_DnsCertRecord) >= udp_payload_length) + { + GNUNET_break_op (0); + return NULL; + } + GNUNET_memcpy (&dcert, &udp_payload[*off], sizeof (struct GNUNET_TUN_DnsCertRecord)); + (*off) += sizeof (struct GNUNET_TUN_DnsCertRecord); + cert = GNUNET_new (struct GNUNET_DNSPARSER_CertRecord); + cert->cert_type = ntohs (dcert.cert_type); + cert->cert_tag = ntohs (dcert.cert_tag); + cert->algorithm = dcert.algorithm; + cert->certificate_size = udp_payload_length - (*off); + cert->certificate_data = GNUNET_malloc (cert->certificate_size); + GNUNET_memcpy (cert->certificate_data, + &udp_payload[*off], + cert->certificate_size); + (*off) += cert->certificate_size; + return cert; +} + + +/** + * Parse a DNS record entry. + * + * @param udp_payload entire UDP payload + * @param udp_payload_length length of @a udp_payload + * @param off pointer to the offset of the record to parse in the udp_payload (to be + * incremented by the size of the record) + * @param r where to write the record information + * @return #GNUNET_OK on success, #GNUNET_SYSERR if the record is malformed + */ +int +GNUNET_DNSPARSER_parse_record (const char *udp_payload, + size_t udp_payload_length, + size_t *off, + struct GNUNET_DNSPARSER_Record *r) +{ + char *name; + struct GNUNET_TUN_DnsRecordLine rl; + size_t old_off; + uint16_t data_len; + + name = GNUNET_DNSPARSER_parse_name (udp_payload, + udp_payload_length, + off); + if (NULL == name) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + r->name = name; + if (*off + sizeof (struct GNUNET_TUN_DnsRecordLine) > udp_payload_length) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_memcpy (&rl, &udp_payload[*off], sizeof (rl)); + (*off) += sizeof (rl); + r->type = ntohs (rl.type); + r->dns_traffic_class = ntohs (rl.dns_traffic_class); + r->expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, + ntohl (rl.ttl))); + data_len = ntohs (rl.data_len); + if (*off + data_len > udp_payload_length) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + old_off = *off; + switch (r->type) + { + case GNUNET_DNSPARSER_TYPE_NS: + case GNUNET_DNSPARSER_TYPE_CNAME: + case GNUNET_DNSPARSER_TYPE_DNAME: + case GNUNET_DNSPARSER_TYPE_PTR: + r->data.hostname = GNUNET_DNSPARSER_parse_name (udp_payload, + udp_payload_length, + off); + if ( (NULL == r->data.hostname) || + (old_off + data_len != *off) ) + return GNUNET_SYSERR; + return GNUNET_OK; + case GNUNET_DNSPARSER_TYPE_SOA: + r->data.soa = GNUNET_DNSPARSER_parse_soa (udp_payload, + udp_payload_length, + off); + if ( (NULL == r->data.soa) || + (old_off + data_len != *off) ) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; + case GNUNET_DNSPARSER_TYPE_MX: + r->data.mx = GNUNET_DNSPARSER_parse_mx (udp_payload, + udp_payload_length, + off); + if ( (NULL == r->data.mx) || + (old_off + data_len != *off) ) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; + case GNUNET_DNSPARSER_TYPE_SRV: + r->data.srv = GNUNET_DNSPARSER_parse_srv (udp_payload, + udp_payload_length, + off); + if ( (NULL == r->data.srv) || + (old_off + data_len != *off) ) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; + default: + r->data.raw.data = GNUNET_malloc (data_len); + r->data.raw.data_len = data_len; + GNUNET_memcpy (r->data.raw.data, + &udp_payload[*off], + data_len); + break; + } + (*off) += data_len; + return GNUNET_OK; +} + + +/** + * Parse a UDP payload of a DNS packet in to a nice struct for further + * processing and manipulation. + * + * @param udp_payload wire-format of the DNS packet + * @param udp_payload_length number of bytes in @a udp_payload + * @return NULL on error, otherwise the parsed packet + */ +struct GNUNET_DNSPARSER_Packet * +GNUNET_DNSPARSER_parse (const char *udp_payload, + size_t udp_payload_length) +{ + struct GNUNET_DNSPARSER_Packet *p; + const struct GNUNET_TUN_DnsHeader *dns; + size_t off; + unsigned int n; + unsigned int i; + + if (udp_payload_length < sizeof (struct GNUNET_TUN_DnsHeader)) + return NULL; + dns = (const struct GNUNET_TUN_DnsHeader *) udp_payload; + off = sizeof (struct GNUNET_TUN_DnsHeader); + p = GNUNET_new (struct GNUNET_DNSPARSER_Packet); + p->flags = dns->flags; + p->id = dns->id; + n = ntohs (dns->query_count); + if (n > 0) + { + p->queries = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Query)); + p->num_queries = n; + for (i=0;iqueries[i])) + goto error; + } + n = ntohs (dns->answer_rcount); + if (n > 0) + { + p->answers = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record)); + p->num_answers = n; + for (i=0;ianswers[i])) + goto error; + } + n = ntohs (dns->authority_rcount); + if (n > 0) + { + p->authority_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record)); + p->num_authority_records = n; + for (i=0;iauthority_records[i])) + goto error; + } + n = ntohs (dns->additional_rcount); + if (n > 0) + { + p->additional_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record)); + p->num_additional_records = n; + for (i=0;iadditional_records[i])) + goto error; + } + return p; + error: + GNUNET_break_op (0); + GNUNET_DNSPARSER_free_packet (p); + return NULL; +} + + +/** + * Free memory taken by a packet. + * + * @param p packet to free + */ +void +GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p) +{ + unsigned int i; + + for (i=0;inum_queries;i++) + GNUNET_free_non_null (p->queries[i].name); + GNUNET_free_non_null (p->queries); + for (i=0;inum_answers;i++) + GNUNET_DNSPARSER_free_record (&p->answers[i]); + GNUNET_free_non_null (p->answers); + for (i=0;inum_authority_records;i++) + GNUNET_DNSPARSER_free_record (&p->authority_records[i]); + GNUNET_free_non_null (p->authority_records); + for (i=0;inum_additional_records;i++) + GNUNET_DNSPARSER_free_record (&p->additional_records[i]); + GNUNET_free_non_null (p->additional_records); + GNUNET_free (p); +} + + +/* ********************** DNS packet assembly code **************** */ + + +/** + * Add a DNS name to the UDP packet at the given location, converting + * the name to IDNA notation as necessary. + * + * @param dst where to write the name (UDP packet) + * @param dst_len number of bytes in @a dst + * @param off pointer to offset where to write the name (increment by bytes used) + * must not be changed if there is an error + * @param name name to write + * @return #GNUNET_SYSERR if @a name is invalid + * #GNUNET_NO if @a name did not fit + * #GNUNET_OK if @a name was added to @a dst + */ +int +GNUNET_DNSPARSER_builder_add_name (char *dst, + size_t dst_len, + size_t *off, + const char *name) +{ + const char *dot; + const char *idna_name; + char *idna_start; + size_t start; + size_t pos; + size_t len; + Idna_rc rc; + + if (NULL == name) + return GNUNET_SYSERR; + + if (IDNA_SUCCESS != + (rc = idna_to_ascii_8z (name, + &idna_start, + IDNA_ALLOW_UNASSIGNED))) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to convert UTF-8 name `%s' to DNS IDNA format: %s\n"), + name, + idna_strerror (rc)); + return GNUNET_NO; + } + idna_name = idna_start; + start = *off; + if (start + strlen (idna_name) + 2 > dst_len) + goto fail; + pos = start; + do + { + dot = strchr (idna_name, '.'); + if (NULL == dot) + len = strlen (idna_name); + else + len = dot - idna_name; + if ( (len >= 64) || (0 == len) ) + { + GNUNET_break (0); + goto fail; /* segment too long or empty */ + } + dst[pos++] = (char) (uint8_t) len; + GNUNET_memcpy (&dst[pos], + idna_name, + len); + pos += len; + idna_name += len + 1; /* also skip dot */ + } + while (NULL != dot); + dst[pos++] = '\0'; /* terminator */ + *off = pos; +#if WINDOWS + idn_free (idna_start); +#else + free (idna_start); +#endif + return GNUNET_OK; + fail: +#if WINDOWS + idn_free (idna_start); +#else + free (idna_start); +#endif + return GNUNET_NO; +} + + +/** + * Add a DNS query to the UDP packet at the given location. + * + * @param dst where to write the query + * @param dst_len number of bytes in @a dst + * @param off pointer to offset where to write the query (increment by bytes used) + * must not be changed if there is an error + * @param query query to write + * @return #GNUNET_SYSERR if @a query is invalid + * #GNUNET_NO if @a query did not fit + * #GNUNET_OK if @a query was added to @a dst + */ +int +GNUNET_DNSPARSER_builder_add_query (char *dst, + size_t dst_len, + size_t *off, + const struct GNUNET_DNSPARSER_Query *query) +{ + int ret; + struct GNUNET_TUN_DnsQueryLine ql; + + ret = GNUNET_DNSPARSER_builder_add_name (dst, dst_len - sizeof (struct GNUNET_TUN_DnsQueryLine), off, query->name); + if (ret != GNUNET_OK) + return ret; + ql.type = htons (query->type); + ql.dns_traffic_class = htons (query->dns_traffic_class); + GNUNET_memcpy (&dst[*off], &ql, sizeof (ql)); + (*off) += sizeof (ql); + return GNUNET_OK; +} + + +/** + * Add an MX record to the UDP packet at the given location. + * + * @param dst where to write the mx record + * @param dst_len number of bytes in @a dst + * @param off pointer to offset where to write the mx information (increment by bytes used); + * can also change if there was an error + * @param mx mx information to write + * @return #GNUNET_SYSERR if @a mx is invalid + * #GNUNET_NO if @a mx did not fit + * #GNUNET_OK if @a mx was added to @a dst + */ +int +GNUNET_DNSPARSER_builder_add_mx (char *dst, + size_t dst_len, + size_t *off, + const struct GNUNET_DNSPARSER_MxRecord *mx) +{ + uint16_t mxpref; + + if (*off + sizeof (uint16_t) > dst_len) + return GNUNET_NO; + mxpref = htons (mx->preference); + GNUNET_memcpy (&dst[*off], + &mxpref, + sizeof (mxpref)); + (*off) += sizeof (mxpref); + return GNUNET_DNSPARSER_builder_add_name (dst, + dst_len, + off, + mx->mxhost); +} + + +/** + * Add a CERT record to the UDP packet at the given location. + * + * @param dst where to write the CERT record + * @param dst_len number of bytes in @a dst + * @param off pointer to offset where to write the CERT information (increment by bytes used); + * can also change if there was an error + * @param cert CERT information to write + * @return #GNUNET_SYSERR if @a cert is invalid + * #GNUNET_NO if @a cert did not fit + * #GNUNET_OK if @a cert was added to @a dst + */ +int +GNUNET_DNSPARSER_builder_add_cert (char *dst, + size_t dst_len, + size_t *off, + const struct GNUNET_DNSPARSER_CertRecord *cert) +{ + struct GNUNET_TUN_DnsCertRecord dcert; + + if ( (cert->cert_type > UINT16_MAX) || + (cert->cert_tag > UINT16_MAX) || + (cert->algorithm > UINT8_MAX) ) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (*off + sizeof (struct GNUNET_TUN_DnsCertRecord) + cert->certificate_size > dst_len) + return GNUNET_NO; + dcert.cert_type = htons ((uint16_t) cert->cert_type); + dcert.cert_tag = htons ((uint16_t) cert->cert_tag); + dcert.algorithm = (uint8_t) cert->algorithm; + GNUNET_memcpy (&dst[*off], &dcert, sizeof (dcert)); + (*off) += sizeof (dcert); + GNUNET_memcpy (&dst[*off], cert->certificate_data, cert->certificate_size); + (*off) += cert->certificate_size; + return GNUNET_OK; +} + + +/** + * Add an SOA record to the UDP packet at the given location. + * + * @param dst where to write the SOA record + * @param dst_len number of bytes in @a dst + * @param off pointer to offset where to write the SOA information (increment by bytes used) + * can also change if there was an error + * @param soa SOA information to write + * @return #GNUNET_SYSERR if @a soa is invalid + * #GNUNET_NO if @a soa did not fit + * #GNUNET_OK if @a soa was added to @a dst + */ +int +GNUNET_DNSPARSER_builder_add_soa (char *dst, + size_t dst_len, + size_t *off, + const struct GNUNET_DNSPARSER_SoaRecord *soa) +{ + struct GNUNET_TUN_DnsSoaRecord sd; + int ret; + + if ( (GNUNET_OK != (ret = GNUNET_DNSPARSER_builder_add_name (dst, + dst_len, + off, + soa->mname))) || + (GNUNET_OK != (ret = GNUNET_DNSPARSER_builder_add_name (dst, + dst_len, + off, + soa->rname)) ) ) + return ret; + if (*off + sizeof (struct GNUNET_TUN_DnsSoaRecord) > dst_len) + return GNUNET_NO; + sd.serial = htonl (soa->serial); + sd.refresh = htonl (soa->refresh); + sd.retry = htonl (soa->retry); + sd.expire = htonl (soa->expire); + sd.minimum = htonl (soa->minimum_ttl); + GNUNET_memcpy (&dst[*off], &sd, sizeof (sd)); + (*off) += sizeof (sd); + return GNUNET_OK; +} + + +/** + * Add an SRV record to the UDP packet at the given location. + * + * @param dst where to write the SRV record + * @param dst_len number of bytes in @a dst + * @param off pointer to offset where to write the SRV information (increment by bytes used) + * can also change if there was an error + * @param srv SRV information to write + * @return #GNUNET_SYSERR if @a srv is invalid + * #GNUNET_NO if @a srv did not fit + * #GNUNET_OK if @a srv was added to @a dst + */ +int +GNUNET_DNSPARSER_builder_add_srv (char *dst, + size_t dst_len, + size_t *off, + const struct GNUNET_DNSPARSER_SrvRecord *srv) +{ + struct GNUNET_TUN_DnsSrvRecord sd; + int ret; + + if (*off + sizeof (struct GNUNET_TUN_DnsSrvRecord) > dst_len) + return GNUNET_NO; + sd.prio = htons (srv->priority); + sd.weight = htons (srv->weight); + sd.port = htons (srv->port); + GNUNET_memcpy (&dst[*off], &sd, sizeof (sd)); + (*off) += sizeof (sd); + if (GNUNET_OK != (ret = GNUNET_DNSPARSER_builder_add_name (dst, + dst_len, + off, + srv->target))) + return ret; + return GNUNET_OK; +} + + +/** + * Add a DNS record to the UDP packet at the given location. + * + * @param dst where to write the query + * @param dst_len number of bytes in @a dst + * @param off pointer to offset where to write the query (increment by bytes used) + * must not be changed if there is an error + * @param record record to write + * @return #GNUNET_SYSERR if @a record is invalid + * #GNUNET_NO if @a record did not fit + * #GNUNET_OK if @a record was added to @a dst + */ +static int +add_record (char *dst, + size_t dst_len, + size_t *off, + const struct GNUNET_DNSPARSER_Record *record) +{ + int ret; + size_t start; + size_t pos; + struct GNUNET_TUN_DnsRecordLine rl; + + start = *off; + ret = GNUNET_DNSPARSER_builder_add_name (dst, + dst_len - sizeof (struct GNUNET_TUN_DnsRecordLine), + off, + record->name); + if (GNUNET_OK != ret) + return ret; + /* '*off' is now the position where we will need to write the record line */ + + pos = *off + sizeof (struct GNUNET_TUN_DnsRecordLine); + switch (record->type) + { + case GNUNET_DNSPARSER_TYPE_MX: + ret = GNUNET_DNSPARSER_builder_add_mx (dst, + dst_len, + &pos, + record->data.mx); + break; + case GNUNET_DNSPARSER_TYPE_CERT: + ret = GNUNET_DNSPARSER_builder_add_cert (dst, + dst_len, + &pos, + record->data.cert); + break; + case GNUNET_DNSPARSER_TYPE_SOA: + ret = GNUNET_DNSPARSER_builder_add_soa (dst, + dst_len, + &pos, + record->data.soa); + break; + case GNUNET_DNSPARSER_TYPE_NS: + case GNUNET_DNSPARSER_TYPE_CNAME: + case GNUNET_DNSPARSER_TYPE_PTR: + ret = GNUNET_DNSPARSER_builder_add_name (dst, + dst_len, + &pos, + record->data.hostname); + break; + case GNUNET_DNSPARSER_TYPE_SRV: + ret = GNUNET_DNSPARSER_builder_add_srv (dst, + dst_len, + &pos, + record->data.srv); + break; + default: + if (pos + record->data.raw.data_len > dst_len) + { + ret = GNUNET_NO; + break; + } + GNUNET_memcpy (&dst[pos], + record->data.raw.data, + record->data.raw.data_len); + pos += record->data.raw.data_len; + ret = GNUNET_OK; + break; + } + if (GNUNET_OK != ret) + { + *off = start; + return GNUNET_NO; + } + + if (pos - (*off + sizeof (struct GNUNET_TUN_DnsRecordLine)) > UINT16_MAX) + { + /* record data too long */ + *off = start; + return GNUNET_NO; + } + rl.type = htons (record->type); + rl.dns_traffic_class = htons (record->dns_traffic_class); + rl.ttl = htonl (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value_us / 1000LL / 1000LL); /* in seconds */ + rl.data_len = htons ((uint16_t) (pos - (*off + sizeof (struct GNUNET_TUN_DnsRecordLine)))); + GNUNET_memcpy (&dst[*off], &rl, sizeof (struct GNUNET_TUN_DnsRecordLine)); + *off = pos; + return GNUNET_OK; +} + + +/** + * Given a DNS packet @a p, generate the corresponding UDP payload. + * Note that we do not attempt to pack the strings with pointers + * as this would complicate the code and this is about being + * simple and secure, not fast, fancy and broken like bind. + * + * @param p packet to pack + * @param max maximum allowed size for the resulting UDP payload + * @param buf set to a buffer with the packed message + * @param buf_length set to the length of @a buf + * @return #GNUNET_SYSERR if @a p is invalid + * #GNUNET_NO if @a p was truncated (but there is still a result in @a buf) + * #GNUNET_OK if @a p was packed completely into @a buf + */ +int +GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p, + uint16_t max, + char **buf, + size_t *buf_length) +{ + struct GNUNET_TUN_DnsHeader dns; + size_t off; + char tmp[max]; + unsigned int i; + int ret; + int trc; + + if ( (p->num_queries > UINT16_MAX) || + (p->num_answers > UINT16_MAX) || + (p->num_authority_records > UINT16_MAX) || + (p->num_additional_records > UINT16_MAX) ) + return GNUNET_SYSERR; + dns.id = p->id; + dns.flags = p->flags; + dns.query_count = htons (p->num_queries); + dns.answer_rcount = htons (p->num_answers); + dns.authority_rcount = htons (p->num_authority_records); + dns.additional_rcount = htons (p->num_additional_records); + + off = sizeof (struct GNUNET_TUN_DnsHeader); + trc = GNUNET_NO; + for (i=0;inum_queries;i++) + { + ret = GNUNET_DNSPARSER_builder_add_query (tmp, + sizeof (tmp), + &off, + &p->queries[i]); + if (GNUNET_SYSERR == ret) + return GNUNET_SYSERR; + if (GNUNET_NO == ret) + { + dns.query_count = htons ((uint16_t) (i-1)); + trc = GNUNET_YES; + break; + } + } + for (i=0;inum_answers;i++) + { + ret = add_record (tmp, + sizeof (tmp), + &off, + &p->answers[i]); + if (GNUNET_SYSERR == ret) + return GNUNET_SYSERR; + if (GNUNET_NO == ret) + { + dns.answer_rcount = htons ((uint16_t) (i-1)); + trc = GNUNET_YES; + break; + } + } + for (i=0;inum_authority_records;i++) + { + ret = add_record (tmp, + sizeof (tmp), + &off, + &p->authority_records[i]); + if (GNUNET_SYSERR == ret) + return GNUNET_SYSERR; + if (GNUNET_NO == ret) + { + dns.authority_rcount = htons ((uint16_t) (i-1)); + trc = GNUNET_YES; + break; + } + } + for (i=0;inum_additional_records;i++) + { + ret = add_record (tmp, + sizeof (tmp), + &off, + &p->additional_records[i]); + if (GNUNET_SYSERR == ret) + return GNUNET_SYSERR; + if (GNUNET_NO == ret) + { + dns.additional_rcount = htons (i-1); + trc = GNUNET_YES; + break; + } + } + + if (GNUNET_YES == trc) + dns.flags.message_truncated = 1; + GNUNET_memcpy (tmp, + &dns, + sizeof (struct GNUNET_TUN_DnsHeader)); + + *buf = GNUNET_malloc (off); + *buf_length = off; + GNUNET_memcpy (*buf, + tmp, + off); + if (GNUNET_YES == trc) + return GNUNET_NO; + return GNUNET_OK; +} + + +/** + * Convert a block of binary data to HEX. + * + * @param data binary data to convert + * @param data_size number of bytes in @a data + * @return HEX string (lower case) + */ +char * +GNUNET_DNSPARSER_bin_to_hex (const void *data, + size_t data_size) +{ + char *ret; + size_t off; + const uint8_t *idata; + + idata = data; + ret = GNUNET_malloc (data_size * 2 + 1); + for (off = 0; off < data_size; off++) + sprintf (&ret[off * 2], + "%02x", + idata[off]); + return ret; +} + + +/** + * Convert a HEX string to block of binary data. + * + * @param hex HEX string to convert (may contain mixed case) + * @param data where to write result, must be + * at least `strlen(hex)/2` bytes long + * @return number of bytes written to data + */ +size_t +GNUNET_DNSPARSER_hex_to_bin (const char *hex, + void *data) +{ + size_t data_size; + size_t off; + uint8_t *idata; + unsigned int h; + char in[3]; + + data_size = strlen (hex) / 2; + idata = data; + in[2] = '\0'; + for (off = 0; off < data_size; off++) + { + in[0] = tolower ((unsigned char) hex[off * 2]); + in[1] = tolower ((unsigned char) hex[off * 2 + 1]); + if (1 != sscanf (in, "%x", &h)) + return off; + idata[off] = (uint8_t) h; + } + return off; +} + + +/* end of dnsparser.c */ diff --git a/src/util/dnsstub.c b/src/util/dnsstub.c new file mode 100644 index 000000000..969ff7beb --- /dev/null +++ b/src/util/dnsstub.c @@ -0,0 +1,749 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012, 2018 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +/** + * @file dns/dnsstub.c + * @brief DNS stub resolver which sends DNS requests to an actual resolver + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_tun_lib.h" +#include "gnunet_dnsstub_lib.h" + +/** + * Timeout for retrying DNS queries. + */ +#define DNS_RETRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250) + + +/** + * DNS Server used for resolution. + */ +struct DnsServer; + + +/** + * UDP socket we are using for sending DNS requests to the Internet. + */ +struct GNUNET_DNSSTUB_RequestSocket +{ + + /** + * UDP socket we use for this request for IPv4 + */ + struct GNUNET_NETWORK_Handle *dnsout4; + + /** + * UDP socket we use for this request for IPv6 + */ + struct GNUNET_NETWORK_Handle *dnsout6; + + /** + * Function to call with result. + */ + GNUNET_DNSSTUB_ResultCallback rc; + + /** + * Closure for @e rc. + */ + void *rc_cls; + + /** + * Task for reading from dnsout4 and dnsout6. + */ + struct GNUNET_SCHEDULER_Task *read_task; + + /** + * Task for retrying transmission of the query. + */ + struct GNUNET_SCHEDULER_Task *retry_task; + + /** + * Next address we sent the DNS request to. + */ + struct DnsServer *ds_pos; + + /** + * Context this request executes in. + */ + struct GNUNET_DNSSTUB_Context *ctx; + + /** + * Query we sent to @e addr. + */ + void *request; + + /** + * Number of bytes in @a request. + */ + size_t request_len; + +}; + + +/** + * DNS Server used for resolution. + */ +struct DnsServer +{ + + /** + * Kept in a DLL. + */ + struct DnsServer *next; + + /** + * Kept in a DLL. + */ + struct DnsServer *prev; + + /** + * IP address of the DNS resolver. + */ + struct sockaddr_storage ss; +}; + + +/** + * Handle to the stub resolver. + */ +struct GNUNET_DNSSTUB_Context +{ + + /** + * Array of all open sockets for DNS requests. + */ + struct GNUNET_DNSSTUB_RequestSocket *sockets; + + /** + * DLL of DNS resolvers we use. + */ + struct DnsServer *dns_head; + + /** + * DLL of DNS resolvers we use. + */ + struct DnsServer *dns_tail; + + /** + * How frequently do we retry requests? + */ + struct GNUNET_TIME_Relative retry_freq; + + /** + * Length of @e sockets array. + */ + unsigned int num_sockets; + +}; + + +/** + * We're done with a `struct GNUNET_DNSSTUB_RequestSocket`, close it for now. + * + * @param rs request socket to clean up + */ +static void +cleanup_rs (struct GNUNET_DNSSTUB_RequestSocket *rs) +{ + if (NULL != rs->dnsout4) + { + GNUNET_NETWORK_socket_close (rs->dnsout4); + rs->dnsout4 = NULL; + } + if (NULL != rs->dnsout6) + { + GNUNET_NETWORK_socket_close (rs->dnsout6); + rs->dnsout6 = NULL; + } + if (NULL != rs->read_task) + { + GNUNET_SCHEDULER_cancel (rs->read_task); + rs->read_task = NULL; + } + if (NULL != rs->retry_task) + { + GNUNET_SCHEDULER_cancel (rs->retry_task); + rs->retry_task = NULL; + } + if (NULL != rs->request) + { + GNUNET_free (rs->request); + rs->request = NULL; + } +} + + +/** + * Open source port for sending DNS requests + * + * @param af AF_INET or AF_INET6 + * @return #GNUNET_OK on success + */ +static struct GNUNET_NETWORK_Handle * +open_socket (int af) +{ + struct sockaddr_in a4; + struct sockaddr_in6 a6; + struct sockaddr *sa; + socklen_t alen; + struct GNUNET_NETWORK_Handle *ret; + + ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0); + if (NULL == ret) + return NULL; + switch (af) + { + case AF_INET: + memset (&a4, 0, alen = sizeof (struct sockaddr_in)); + sa = (struct sockaddr *) &a4; + break; + case AF_INET6: + memset (&a6, 0, alen = sizeof (struct sockaddr_in6)); + sa = (struct sockaddr *) &a6; + break; + default: + GNUNET_break (0); + GNUNET_NETWORK_socket_close (ret); + return NULL; + } + sa->sa_family = af; + if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret, + sa, + alen)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not bind to any port: %s\n"), + STRERROR (errno)); + GNUNET_NETWORK_socket_close (ret); + return NULL; + } + return ret; +} + + +/** + * Get a socket of the specified address family to send out a + * UDP DNS request to the Internet. + * + * @param ctx the DNSSTUB context + * @return NULL on error + */ +static struct GNUNET_DNSSTUB_RequestSocket * +get_request_socket (struct GNUNET_DNSSTUB_Context *ctx) +{ + struct GNUNET_DNSSTUB_RequestSocket *rs; + + for (unsigned int i=0;i<256;i++) + { + rs = &ctx->sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, + ctx->num_sockets)]; + if (NULL == rs->rc) + break; + } + if (NULL != rs->rc) + { + /* signal "failure" */ + rs->rc (rs->rc_cls, + NULL, + 0); + rs->rc = NULL; + } + if (NULL != rs->read_task) + { + GNUNET_SCHEDULER_cancel (rs->read_task); + rs->read_task = NULL; + } + if (NULL != rs->retry_task) + { + GNUNET_SCHEDULER_cancel (rs->retry_task); + rs->retry_task = NULL; + } + if (NULL != rs->request) + { + GNUNET_free (rs->request); + rs->request = NULL; + } + rs->ctx = ctx; + return rs; +} + + +/** + * Actually do the reading of a DNS packet from our UDP socket and see + * if we have a valid, matching, pending request. + * + * @param rs request socket with callback details + * @param dnsout socket to read from + * @return #GNUNET_OK on success, #GNUNET_NO on drop, #GNUNET_SYSERR on IO-errors (closed socket) + */ +static int +do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs, + struct GNUNET_NETWORK_Handle *dnsout) +{ + struct GNUNET_DNSSTUB_Context *ctx = rs->ctx; + ssize_t r; + int len; + +#ifndef MINGW + if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), + FIONREAD, + &len)) + { + /* conservative choice: */ + len = UINT16_MAX; + } +#else + /* port the code above? */ + len = UINT16_MAX; +#endif + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Receiving %d byte DNS reply\n", + len); + { + unsigned char buf[len] GNUNET_ALIGN; + int found; + struct sockaddr_storage addr; + socklen_t addrlen; + struct GNUNET_TUN_DnsHeader *dns; + + addrlen = sizeof (addr); + memset (&addr, + 0, + sizeof (addr)); + r = GNUNET_NETWORK_socket_recvfrom (dnsout, + buf, + sizeof (buf), + (struct sockaddr*) &addr, + &addrlen); + if (-1 == r) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "recvfrom"); + GNUNET_NETWORK_socket_close (dnsout); + return GNUNET_SYSERR; + } + found = GNUNET_NO; + for (struct DnsServer *ds = ctx->dns_head; NULL != ds; ds = ds->next) + { + if (0 == memcmp (&addr, + &ds->ss, + GNUNET_MIN (sizeof (struct sockaddr_storage), + addrlen))) + { + found = GNUNET_YES; + break; + } + } + if (GNUNET_NO == found) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received DNS response from server we never asked (ignored)"); + return GNUNET_NO; + } + if (sizeof (struct GNUNET_TUN_DnsHeader) > r) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Received DNS response that is too small (%u bytes)"), + (unsigned int) r); + return GNUNET_NO; + } + dns = (struct GNUNET_TUN_DnsHeader *) buf; + if (NULL == rs->rc) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Request timeout or cancelled; ignoring reply\n"); + return GNUNET_NO; + } + rs->rc (rs->rc_cls, + dns, + r); + } + return GNUNET_OK; +} + + +/** + * Read a DNS response from the (unhindered) UDP-Socket + * + * @param cls socket to read from + */ +static void +read_response (void *cls); + + +/** + * Schedule #read_response() task for @a rs. + * + * @param rs request to schedule read operation for + */ +static void +schedule_read (struct GNUNET_DNSSTUB_RequestSocket *rs) +{ + struct GNUNET_NETWORK_FDSet *rset; + + if (NULL != rs->read_task) + GNUNET_SCHEDULER_cancel (rs->read_task); + rset = GNUNET_NETWORK_fdset_create (); + if (NULL != rs->dnsout4) + GNUNET_NETWORK_fdset_set (rset, + rs->dnsout4); + if (NULL != rs->dnsout6) + GNUNET_NETWORK_fdset_set (rset, + rs->dnsout6); + rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_TIME_UNIT_FOREVER_REL, + rset, + NULL, + &read_response, + rs); + GNUNET_NETWORK_fdset_destroy (rset); +} + + +/** + * Read a DNS response from the (unhindered) UDP-Socket + * + * @param cls `struct GNUNET_DNSSTUB_RequestSocket` to read from + */ +static void +read_response (void *cls) +{ + struct GNUNET_DNSSTUB_RequestSocket *rs = cls; + const struct GNUNET_SCHEDULER_TaskContext *tc; + + rs->read_task = NULL; + tc = GNUNET_SCHEDULER_get_task_context (); + /* read and process ready sockets */ + if ( (NULL != rs->dnsout4) && + (GNUNET_NETWORK_fdset_isset (tc->read_ready, + rs->dnsout4)) && + (GNUNET_SYSERR == + do_dns_read (rs, + rs->dnsout4)) ) + rs->dnsout4 = NULL; + if ( (NULL != rs->dnsout6) && + (GNUNET_NETWORK_fdset_isset (tc->read_ready, + rs->dnsout6)) && + (GNUNET_SYSERR == + do_dns_read (rs, + rs->dnsout6)) ) + rs->dnsout6 = NULL; + /* re-schedule read task */ + schedule_read (rs); +} + + +/** + * Task to (re)transmit the DNS query, possibly repeatedly until + * we succeed. + * + * @param cls our `struct GNUNET_DNSSTUB_RequestSocket *` + */ +static void +transmit_query (void *cls) +{ + struct GNUNET_DNSSTUB_RequestSocket *rs = cls; + struct GNUNET_DNSSTUB_Context *ctx = rs->ctx; + const struct sockaddr *sa; + socklen_t salen; + struct DnsServer *ds; + struct GNUNET_NETWORK_Handle *dnsout; + + rs->retry_task = GNUNET_SCHEDULER_add_delayed (ctx->retry_freq, + &transmit_query, + rs); + ds = rs->ds_pos; + rs->ds_pos = ds->next; + if (NULL == rs->ds_pos) + rs->ds_pos = ctx->dns_head; + GNUNET_assert (NULL != ds); + dnsout = NULL; + switch (ds->ss.ss_family) + { + case AF_INET: + if (NULL == rs->dnsout4) + rs->dnsout4 = open_socket (AF_INET); + dnsout = rs->dnsout4; + sa = (const struct sockaddr *) &ds->ss; + salen = sizeof (struct sockaddr_in); + break; + case AF_INET6: + if (NULL == rs->dnsout6) + rs->dnsout6 = open_socket (AF_INET6); + dnsout = rs->dnsout6; + sa = (const struct sockaddr *) &ds->ss; + salen = sizeof (struct sockaddr_in6); + break; + default: + return; + } + if (NULL == dnsout) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to use configure DNS server, skipping\n"); + return; + } + if (GNUNET_SYSERR == + GNUNET_NETWORK_socket_sendto (dnsout, + rs->request, + rs->request_len, + sa, + salen)) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to send DNS request to %s: %s\n"), + GNUNET_a2s (sa, + salen), + STRERROR (errno)); + else + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Sent DNS request to %s\n"), + GNUNET_a2s (sa, + salen)); + schedule_read (rs); +} + + +/** + * Perform DNS resolution using our default IP from init. + * + * @param ctx stub resolver to use + * @param request DNS request to transmit + * @param request_len number of bytes in msg + * @param rc function to call with result + * @param rc_cls closure for 'rc' + * @return socket used for the request, NULL on error + */ +struct GNUNET_DNSSTUB_RequestSocket * +GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx, + const void *request, + size_t request_len, + GNUNET_DNSSTUB_ResultCallback rc, + void *rc_cls) +{ + struct GNUNET_DNSSTUB_RequestSocket *rs; + + if (NULL == ctx->dns_head) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No DNS server configured for resolution\n"); + return NULL; + } + if (NULL == (rs = get_request_socket (ctx))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No request socket available for DNS resolution\n"); + return NULL; + } + rs->ds_pos = ctx->dns_head; + rs->rc = rc; + rs->rc_cls = rc_cls; + rs->request = GNUNET_memdup (request, + request_len); + rs->request_len = request_len; + rs->retry_task = GNUNET_SCHEDULER_add_now (&transmit_query, + rs); + return rs; +} + + +/** + * Cancel DNS resolution. + * + * @param rs resolution to cancel + */ +void +GNUNET_DNSSTUB_resolve_cancel (struct GNUNET_DNSSTUB_RequestSocket *rs) +{ + rs->rc = NULL; + if (NULL != rs->retry_task) + { + GNUNET_SCHEDULER_cancel (rs->retry_task); + rs->retry_task = NULL; + } + if (NULL != rs->read_task) + { + GNUNET_SCHEDULER_cancel (rs->read_task); + rs->read_task = NULL; + } +} + + +/** + * Start a DNS stub resolver. + * + * @param num_sockets how many sockets should we open + * in parallel for DNS queries for this stub? + * @return NULL on error + */ +struct GNUNET_DNSSTUB_Context * +GNUNET_DNSSTUB_start (unsigned int num_sockets) +{ + struct GNUNET_DNSSTUB_Context *ctx; + + if (0 == num_sockets) + { + GNUNET_break (0); + return NULL; + } + ctx = GNUNET_new (struct GNUNET_DNSSTUB_Context); + ctx->num_sockets = num_sockets; + ctx->sockets = GNUNET_new_array (num_sockets, + struct GNUNET_DNSSTUB_RequestSocket); + ctx->retry_freq = DNS_RETRANSMIT_DELAY; + return ctx; +} + + +/** + * Add nameserver for use by the DNSSTUB. We will use + * all provided nameservers for resolution (round-robin). + * + * @param ctx resolver context to modify + * @param dns_ip target IP address to use (as string) + * @return #GNUNET_OK on success + */ +int +GNUNET_DNSSTUB_add_dns_ip (struct GNUNET_DNSSTUB_Context *ctx, + const char *dns_ip) +{ + struct DnsServer *ds; + struct in_addr i4; + struct in6_addr i6; + + ds = GNUNET_new (struct DnsServer); + if (1 == inet_pton (AF_INET, + dns_ip, + &i4)) + { + struct sockaddr_in *s4 = (struct sockaddr_in *) &ds->ss; + + s4->sin_family = AF_INET; + s4->sin_port = htons (53); + s4->sin_addr = i4; +#if HAVE_SOCKADDR_IN_SIN_LEN + s4->sin_len = (u_char) sizeof (struct sockaddr_in); +#endif + } + else if (1 == inet_pton (AF_INET6, + dns_ip, + &i6)) + { + struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &ds->ss; + + s6->sin6_family = AF_INET6; + s6->sin6_port = htons (53); + s6->sin6_addr = i6; +#if HAVE_SOCKADDR_IN_SIN_LEN + s6->sin6_len = (u_char) sizeof (struct sockaddr_in6); +#endif + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Malformed IP address `%s' for DNS server\n", + dns_ip); + GNUNET_free (ds); + return GNUNET_SYSERR; + } + GNUNET_CONTAINER_DLL_insert (ctx->dns_head, + ctx->dns_tail, + ds); + return GNUNET_OK; +} + + +/** + * Add nameserver for use by the DNSSTUB. We will use + * all provided nameservers for resolution (round-robin). + * + * @param ctx resolver context to modify + * @param sa socket address of DNS resolver to use + * @return #GNUNET_OK on success + */ +int +GNUNET_DNSSTUB_add_dns_sa (struct GNUNET_DNSSTUB_Context *ctx, + const struct sockaddr *sa) +{ + struct DnsServer *ds; + + ds = GNUNET_new (struct DnsServer); + switch (sa->sa_family) + { + case AF_INET: + GNUNET_memcpy (&ds->ss, + sa, + sizeof (struct sockaddr_in)); + break; + case AF_INET6: + GNUNET_memcpy (&ds->ss, + sa, + sizeof (struct sockaddr_in6)); + break; + default: + GNUNET_break (0); + GNUNET_free (ds); + return GNUNET_SYSERR; + } + GNUNET_CONTAINER_DLL_insert (ctx->dns_head, + ctx->dns_tail, + ds); + return GNUNET_OK; +} + + +/** + * How long should we try requests before timing out? + * Only effective for requests issued after this call. + * + * @param ctx resolver context to modify + * @param retry_freq how long to wait between retries + */ +void +GNUNET_DNSSTUB_set_retry (struct GNUNET_DNSSTUB_Context *ctx, + struct GNUNET_TIME_Relative retry_freq) +{ + ctx->retry_freq = retry_freq; +} + + +/** + * Cleanup DNSSTUB resolver. + * + * @param ctx stub resolver to clean up + */ +void +GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx) +{ + struct DnsServer *ds; + + while (NULL != (ds = ctx->dns_head)) + { + GNUNET_CONTAINER_DLL_remove (ctx->dns_head, + ctx->dns_tail, + ds); + GNUNET_free (ds); + } + for (unsigned int i=0;inum_sockets;i++) + cleanup_rs (&ctx->sockets[i]); + GNUNET_free (ctx->sockets); + GNUNET_free (ctx); +} + + +/* end of dnsstub.c */ diff --git a/src/util/regex.c b/src/util/regex.c new file mode 100644 index 000000000..7565a9eac --- /dev/null +++ b/src/util/regex.c @@ -0,0 +1,834 @@ +/* + This file is part of GNUnet + Copyright (C) 2012, 2013, 2015 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +/** + * @file src/tun/regex.c + * @brief functions to convert IP networks to regexes + * @author Maximilian Szengel + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_tun_lib.h" + +/** + * 'wildcard', matches all possible values (for HEX encoding). + */ +#define DOT "(0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)" + + +/** + * Create a regex in @a rxstr from the given @a ip and @a netmask. + * + * @param ip IPv4 representation. + * @param port destination port + * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV4_REGEXLEN + * bytes long. + */ +void +GNUNET_TUN_ipv4toregexsearch (const struct in_addr *ip, + uint16_t port, + char *rxstr) +{ + GNUNET_snprintf (rxstr, + GNUNET_TUN_IPV4_REGEXLEN, + "4-%04X-%08X", + (unsigned int) port, + ntohl (ip->s_addr)); +} + + +/** + * Create a regex in @a rxstr from the given @a ipv6 and @a prefixlen. + * + * @param ipv6 IPv6 representation. + * @param port destination port + * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV6_REGEXLEN + * bytes long. + */ +void +GNUNET_TUN_ipv6toregexsearch (const struct in6_addr *ipv6, + uint16_t port, + char *rxstr) +{ + const uint32_t *addr; + + addr = (const uint32_t *) ipv6; + GNUNET_snprintf (rxstr, + GNUNET_TUN_IPV6_REGEXLEN, + "6-%04X-%08X%08X%08X%08X", + (unsigned int) port, + ntohl (addr[0]), + ntohl (addr[1]), + ntohl (addr[2]), + ntohl (addr[3])); +} + + +/** + * Convert the given 4-bit (!) number to a regex. + * + * @param value the value, only the lowest 4 bits will be looked at + * @param mask which bits in value are wildcards (any value)? + */ +static char * +nibble_to_regex (uint8_t value, + uint8_t mask) +{ + char *ret; + + value &= mask; + switch (mask) + { + case 0: + return GNUNET_strdup (DOT); + case 8: + GNUNET_asprintf (&ret, + "(%X|%X|%X|%X|%X|%X|%X|%X)", + value, + value + 1, + value + 2, + value + 3, + value + 4, + value + 5, + value + 6, + value + 7); + return ret; + case 12: + GNUNET_asprintf (&ret, + "(%X|%X|%X|%X)", + value, + value + 1, + value + 2, + value + 3); + return ret; + case 14: + GNUNET_asprintf (&ret, + "(%X|%X)", + value, + value + 1); + return ret; + case 15: + GNUNET_asprintf (&ret, + "%X", + value); + return ret; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Bad mask: %d\n"), + mask); + GNUNET_break (0); + return NULL; + } +} + + +/** + * Convert the given 16-bit number to a regex. + * + * @param value the value + * @param mask which bits in value are wildcards (any value)? + */ +static char * +num_to_regex (uint16_t value, + uint16_t mask) +{ + const uint8_t *v = (const uint8_t *) &value; + const uint8_t *m = (const uint8_t *) &mask; + char *a; + char *b; + char *c; + char *d; + char *ret; + + a = nibble_to_regex (v[0] >> 4, m[0] >> 4); + b = nibble_to_regex (v[0] & 15, m[0] & 15); + c = nibble_to_regex (v[1] >> 4, m[1] >> 4); + d = nibble_to_regex (v[1] & 15, m[1] & 15); + ret = NULL; + if ( (NULL != a) && + (NULL != b) && + (NULL != c) && + (NULL != d) ) + GNUNET_asprintf (&ret, + "%s%s%s%s", + a, b, c, d); + GNUNET_free_non_null (a); + GNUNET_free_non_null (b); + GNUNET_free_non_null (c); + GNUNET_free_non_null (d); + return ret; +} + + +/** + * Do we need to put parents around the given argument? + * + * @param arg part of a regular expression + * @return #GNUNET_YES if we should parens, + * #GNUNET_NO if not + */ +static int +needs_parens (const char *arg) +{ + size_t off; + size_t len; + unsigned int op; + + op = 0; + len = strlen (arg); + for (off=0;off 0); + op--; + break; + case '|': + if (0 == op) + return GNUNET_YES; + break; + default: + break; + } + } + return GNUNET_NO; +} + + +/** + * Compute port policy for the given range of + * port numbers. + * + * @param start starting offset + * @param end end offset + * @param step increment level (power of 16) + * @param pp port policy to convert + * @return corresponding regex + */ +static char * +compute_policy (unsigned int start, + unsigned int end, + unsigned int step, + const struct GNUNET_STRINGS_PortPolicy *pp) +{ + unsigned int i; + char before[36]; /* 16 * 2 + 3 dots + 0-terminator */ + char middlel[33]; /* 16 * 2 + 0-terminator */ + char middleh[33]; /* 16 * 2 + 0-terminator */ + char after[36]; /* 16 * 2 + 3 dots + 0-terminator */ + char beforep[36+2]; /* 16 * 2 + 3 dots + 0-terminator + ()*/ + char middlehp[33+2]; /* 16 * 2 + 0-terminator + () */ + char middlelp[33+2]; /* 16 * 2 + 0-terminator + () */ + char afterp[36+2]; /* 16 * 2 + 3 dots + 0-terminator + () */ + char dots[5 * strlen (DOT)]; + char buf[3]; + char *middle; + char *ret; + unsigned int xstep; + char *recl; + char *rech; + char *reclp; + char *rechp; + unsigned int start_port; + unsigned int end_port; + + GNUNET_assert (GNUNET_YES == pp->negate_portrange); + start_port = pp->start_port; + if (1 == start_port) + start_port = 0; + end_port = pp->end_port; + GNUNET_assert ((end - start) / step <= 0xF); + before[0] = '\0'; + middlel[0] = '\0'; + middleh[0] = '\0'; + after[0] = '\0'; + for (i=start;i<=end;i+=step) + { + GNUNET_snprintf (buf, + sizeof (buf), + "%X|", + (i - start) / step); + if (i / step < start_port / step) + strcat (before, buf); + else if (i / step > end_port / step) + strcat (after, buf); + else if (i / step == start_port / step) + strcat (middlel, buf); + else if (i / step == end_port / step) + strcat (middleh, buf); + } + if (strlen (before) > 0) + before[strlen (before)-1] = '\0'; + if (strlen (middlel) > 0) + middlel[strlen (middlel)-1] = '\0'; + if (strlen (middleh) > 0) + middleh[strlen (middleh)-1] = '\0'; + if (strlen (after) > 0) + after[strlen (after)-1] = '\0'; + if (needs_parens (before)) + GNUNET_snprintf (beforep, + sizeof (beforep), + "(%s)", + before); + else + strcpy (beforep, before); + if (needs_parens (middlel)) + GNUNET_snprintf (middlelp, + sizeof (middlelp), + "(%s)", + middlel); + else + strcpy (middlelp, middlel); + if (needs_parens (middleh)) + GNUNET_snprintf (middlehp, + sizeof (middlehp), + "(%s)", + middleh); + else + strcpy (middlehp, middleh); + if (needs_parens (after)) + GNUNET_snprintf (afterp, + sizeof (afterp), + "(%s)", + after); + else + strcpy (afterp, after); + dots[0] = '\0'; + for (xstep=step/16;xstep>0;xstep/=16) + strcat (dots, DOT); + if (step >= 16) + { + if (strlen (middlel) > 0) + recl = compute_policy ((start_port / step) * step, + (start_port / step) * step + step - 1, + step / 16, + pp); + else + recl = GNUNET_strdup (""); + if (strlen (middleh) > 0) + rech = compute_policy ((end_port / step) * step, + (end_port / step) * step + step - 1, + step / 16, + pp); + else + rech = GNUNET_strdup (""); + } + else + { + recl = GNUNET_strdup (""); + rech = GNUNET_strdup (""); + middlel[0] = '\0'; + middlelp[0] = '\0'; + middleh[0] = '\0'; + middlehp[0] = '\0'; + } + if (needs_parens (recl)) + GNUNET_asprintf (&reclp, + "(%s)", + recl); + else + reclp = GNUNET_strdup (recl); + if (needs_parens (rech)) + GNUNET_asprintf (&rechp, + "(%s)", + rech); + else + rechp = GNUNET_strdup (rech); + + if ( (strlen (middleh) > 0) && + (strlen (rech) > 0) && + (strlen (middlel) > 0) && + (strlen (recl) > 0) ) + { + GNUNET_asprintf (&middle, + "%s%s|%s%s", + middlel, + reclp, + middleh, + rechp); + } + else if ( (strlen (middleh) > 0) && + (strlen (rech) > 0) ) + { + GNUNET_asprintf (&middle, + "%s%s", + middleh, + rechp); + } + else if ( (strlen (middlel) > 0) && + (strlen (recl) > 0) ) + { + GNUNET_asprintf (&middle, + "%s%s", + middlel, + reclp); + } + else + { + middle = GNUNET_strdup (""); + } + if ( (strlen(before) > 0) && + (strlen(after) > 0) ) + { + if (strlen (dots) > 0) + { + if (strlen (middle) > 0) + GNUNET_asprintf (&ret, + "(%s%s|%s|%s%s)", + beforep, dots, + middle, + afterp, dots); + else + GNUNET_asprintf (&ret, + "(%s|%s)%s", + beforep, + afterp, + dots); + } + else + { + if (strlen (middle) > 0) + GNUNET_asprintf (&ret, + "(%s|%s|%s)", + before, + middle, + after); + else if (1 == step) + GNUNET_asprintf (&ret, + "%s|%s", + before, + after); + else + GNUNET_asprintf (&ret, + "(%s|%s)", + before, + after); + } + } + else if (strlen (before) > 0) + { + if (strlen (dots) > 0) + { + if (strlen (middle) > 0) + GNUNET_asprintf (&ret, + "(%s%s|%s)", + beforep, dots, + middle); + else + GNUNET_asprintf (&ret, + "%s%s", + beforep, dots); + } + else + { + if (strlen (middle) > 0) + GNUNET_asprintf (&ret, + "(%s|%s)", + before, + middle); + else + GNUNET_asprintf (&ret, + "%s", + before); + } + } + else if (strlen (after) > 0) + { + if (strlen (dots) > 0) + { + if (strlen (middle) > 0) + GNUNET_asprintf (&ret, + "(%s|%s%s)", + middle, + afterp, dots); + else + GNUNET_asprintf (&ret, + "%s%s", + afterp, dots); + } + else + { + if (strlen (middle) > 0) + GNUNET_asprintf (&ret, + "%s|%s", + middle, + after); + else + GNUNET_asprintf (&ret, + "%s", + after); + } + } + else if (strlen (middle) > 0) + { + GNUNET_asprintf (&ret, + "%s", + middle); + } + else + { + ret = GNUNET_strdup (""); + } + GNUNET_free (middle); + GNUNET_free (reclp); + GNUNET_free (rechp); + GNUNET_free (recl); + GNUNET_free (rech); + return ret; +} + + +/** + * Convert a port policy to a regular expression. Note: this is a + * very simplistic implementation, we might want to consider doing + * something more sophisiticated (resulting in smaller regular + * expressions) at a later time. + * + * @param pp port policy to convert + * @return NULL on error + */ +static char * +port_to_regex (const struct GNUNET_STRINGS_PortPolicy *pp) +{ + char *reg; + char *ret; + char *pos; + unsigned int i; + unsigned int cnt; + + if ( (0 == pp->start_port) || + ( (1 == pp->start_port) && + (0xFFFF == pp->end_port) && + (GNUNET_NO == pp->negate_portrange)) ) + return GNUNET_strdup (DOT DOT DOT DOT); + if ( (pp->start_port == pp->end_port) && + (GNUNET_NO == pp->negate_portrange)) + { + GNUNET_asprintf (&ret, + "%04X", + pp->start_port); + return ret; + } + if (pp->end_port < pp->start_port) + return NULL; + + if (GNUNET_YES == pp->negate_portrange) + { + ret = compute_policy (0, 0xFFFF, 0x1000, pp); + } + else + { + cnt = pp->end_port - pp->start_port + 1; + reg = GNUNET_malloc (cnt * 5 + 1); + pos = reg; + for (i=1;i<=0xFFFF;i++) + { + if ( (i >= pp->start_port) && (i <= pp->end_port) ) + { + if (pos == reg) + { + GNUNET_snprintf (pos, + 5, + "%04X", + i); + } + else + { + GNUNET_snprintf (pos, + 6, + "|%04X", + i); + } + pos += strlen (pos); + } + } + GNUNET_asprintf (&ret, + "(%s)", + reg); + GNUNET_free (reg); + } + return ret; +} + + +/** + * Convert an address (IPv4 or IPv6) to a regex. + * + * @param addr address + * @param mask network mask + * @param len number of bytes in @a addr and @a mask + * @return NULL on error, otherwise regex for the address + */ +static char * +address_to_regex (const void *addr, + const void *mask, + size_t len) +{ + const uint16_t *a = addr; + const uint16_t *m = mask; + char *ret; + char *tmp; + char *reg; + unsigned int i; + + ret = NULL; + GNUNET_assert (1 != (len % 2)); + for (i=0;inetwork, + &v4->netmask, + sizeof (struct in_addr)); + if (NULL == reg) + return NULL; + pp = port_to_regex (&v4->pp); + if (NULL == pp) + { + GNUNET_free (reg); + return NULL; + } + GNUNET_asprintf (&ret, + "4-%s-%s", + pp, reg); + GNUNET_free (pp); + GNUNET_free (reg); + return ret; +} + + +/** + * Convert a single line of an IPv4 policy to a regular expression. + * + * @param v6 line to convert + * @return NULL on error + */ +static char * +ipv6_to_regex (const struct GNUNET_STRINGS_IPv6NetworkPolicy *v6) +{ + char *reg; + char *pp; + char *ret; + + reg = address_to_regex (&v6->network, + &v6->netmask, + sizeof (struct in6_addr)); + if (NULL == reg) + return NULL; + pp = port_to_regex (&v6->pp); + if (NULL == pp) + { + GNUNET_free (reg); + return NULL; + } + GNUNET_asprintf (&ret, + "6-%s-%s", + pp, reg); + GNUNET_free (pp); + GNUNET_free (reg); + return ret; +} + + +/** + * Convert an exit policy to a regular expression. The exit policy + * specifies a set of subnets this peer is willing to serve as an + * exit for; the resulting regular expression will match the + * IPv4 address strings as returned by #GNUNET_TUN_ipv4toregexsearch(). + * + * @param policy exit policy specification + * @return regular expression, NULL on error + */ +char * +GNUNET_TUN_ipv4policy2regex (const char *policy) +{ + struct GNUNET_STRINGS_IPv4NetworkPolicy *np; + char *reg; + char *tmp; + char *line; + unsigned int i; + + np = GNUNET_STRINGS_parse_ipv4_policy (policy); + if (NULL == np) + return NULL; + reg = NULL; + for (i=0; (0 == i) || (0 != np[i].network.s_addr); i++) + { + line = ipv4_to_regex (&np[i]); + if (NULL == line) + { + GNUNET_free_non_null (reg); + GNUNET_free (np); + return NULL; + } + if (NULL == reg) + { + reg = line; + } + else + { + GNUNET_asprintf (&tmp, + "%s|(%s)", + reg, line); + GNUNET_free (reg); + GNUNET_free (line); + reg = tmp; + } + if (0 == np[i].network.s_addr) + break; + } + GNUNET_free (np); + return reg; +} + + +/** + * Convert an exit policy to a regular expression. The exit policy + * specifies a set of subnets this peer is willing to serve as an + * exit for; the resulting regular expression will match the + * IPv6 address strings as returned by #GNUNET_TUN_ipv6toregexsearch(). + * + * @param policy exit policy specification + * @return regular expression, NULL on error + */ +char * +GNUNET_TUN_ipv6policy2regex (const char *policy) +{ + struct in6_addr zero; + struct GNUNET_STRINGS_IPv6NetworkPolicy *np; + char *reg; + char *tmp; + char *line; + unsigned int i; + + np = GNUNET_STRINGS_parse_ipv6_policy (policy); + if (NULL == np) + return NULL; + reg = NULL; + memset (&zero, 0, sizeof (struct in6_addr)); + for (i=0; (0 == i) || (0 != memcmp (&zero, &np[i].network, sizeof (struct in6_addr))); i++) + { + line = ipv6_to_regex (&np[i]); + if (NULL == line) + { + GNUNET_free_non_null (reg); + GNUNET_free (np); + return NULL; + } + if (NULL == reg) + { + reg = line; + } + else + { + GNUNET_asprintf (&tmp, + "%s|(%s)", + reg, line); + GNUNET_free (reg); + GNUNET_free (line); + reg = tmp; + } + if (0 == memcmp (&zero, &np[i].network, sizeof (struct in6_addr))) + break; + } + GNUNET_free (np); + return reg; +} + + +/** + * Hash the service name of a hosted service to the + * hash code that is used to identify the service on + * the network. + * + * @param service_name a string + * @param hc corresponding hash + */ +void +GNUNET_TUN_service_name_to_hash (const char *service_name, + struct GNUNET_HashCode *hc) +{ + GNUNET_CRYPTO_hash (service_name, + strlen (service_name), + hc); +} + + +/** + * Compute the CADET port given a service descriptor + * (returned from #GNUNET_TUN_service_name_to_hash) and + * a TCP/UDP port @a ip_port. + * + * @param desc service shared secret + * @param ip_port TCP/UDP port, use 0 for ICMP + * @param[out] cadet_port CADET port to use + */ +void +GNUNET_TUN_compute_service_cadet_port (const struct GNUNET_HashCode *desc, + uint16_t ip_port, + struct GNUNET_HashCode *cadet_port) +{ + uint16_t be_port = htons (ip_port); + + *cadet_port = *desc; + GNUNET_memcpy (cadet_port, + &be_port, + sizeof (uint16_t)); +} + + +/* end of regex.c */ diff --git a/src/util/test_regex.c b/src/util/test_regex.c new file mode 100644 index 000000000..2e7d52828 --- /dev/null +++ b/src/util/test_regex.c @@ -0,0 +1,179 @@ +/* + This file is part of GNUnet + Copyright (C) 2012, 2013 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +/** + * @file tun/test_regex.c + * @brief simple test for regex.c iptoregex functions + * @author Maximilian Szengel + */ +#include "platform.h" +#include "gnunet_tun_lib.h" + +/** + * 'wildcard', matches all possible values (for HEX encoding). + */ +#define DOT "(0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)" + + +static int +test_iptoregex (const char *ipv4, + uint16_t port, + const char *expectedv4, + const char *ipv6, + uint16_t port6, + const char *expectedv6) +{ + int error = 0; + + struct in_addr a; + struct in6_addr b; + char rxv4[GNUNET_TUN_IPV4_REGEXLEN]; + char rxv6[GNUNET_TUN_IPV6_REGEXLEN]; + + GNUNET_assert (1 == inet_pton (AF_INET, ipv4, &a)); + GNUNET_TUN_ipv4toregexsearch (&a, port, rxv4); + + if (0 != strcmp (rxv4, expectedv4)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected: %s but got: %s\n", + expectedv4, + rxv4); + error++; + } + + GNUNET_assert (1 == inet_pton (AF_INET6, ipv6, &b)); + GNUNET_TUN_ipv6toregexsearch (&b, port6, rxv6); + if (0 != strcmp (rxv6, expectedv6)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected: %s but got: %s\n", + expectedv6, rxv6); + error++; + } + return error; +} + + +static int +test_policy4toregex (const char *policy, + const char *regex) +{ + char *r; + int ret; + + ret = 0; + r = GNUNET_TUN_ipv4policy2regex (policy); + if (NULL == r) + { + GNUNET_break (0); + return 1; + } + if (0 != strcmp (regex, r)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected: `%s' but got: `%s'\n", + regex, r); + ret = 2; + } + GNUNET_free (r); + return ret; +} + + +static int +test_policy6toregex (const char *policy, + const char *regex) +{ + char *r; + int ret; + + ret = 0; + r = GNUNET_TUN_ipv6policy2regex (policy); + if (NULL == r) + { + GNUNET_break (0); + return 1; + } + if (0 != strcmp (regex, r)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected: `%s' but got: `%s'\n", + regex, r); + ret = 2; + } + GNUNET_free (r); + return ret; +} + + +int +main (int argc, char *argv[]) +{ + int error; + char *r; + + GNUNET_log_setup ("test-regex", "WARNING", NULL); + error = 0; + + /* this is just a performance test ... */ + r = GNUNET_TUN_ipv4policy2regex ("1.2.3.4/16:!25;"); + GNUNET_break (NULL != r); + GNUNET_free (r); + + error += + test_iptoregex ("192.1.2.3", 2086, + "4-0826-C0010203", + "FFFF::1", 8080, + "6-1F90-FFFF0000000000000000000000000001"); + error += + test_iptoregex ("187.238.255.0", 80, + "4-0050-BBEEFF00", + "E1E1:73F9:51BE::0", 49, + "6-0031-E1E173F951BE00000000000000000000"); + error += + test_policy4toregex ("192.1.2.0/24:80;", + "4-0050-C00102" DOT DOT); + error += + test_policy4toregex ("192.1.0.0/16;", + "4-" DOT DOT DOT DOT "-C001" DOT DOT DOT DOT); + error += + test_policy4toregex ("192.1.0.0/16:80-81;", + "4-(0050|0051)-C001" DOT DOT DOT DOT); + error += + test_policy4toregex ("192.1.0.0/8:!3-65535;", + "4-000(0|1|2)-C0" DOT DOT DOT DOT DOT DOT); + error += + test_policy4toregex ("192.1.0.0/8:!25-56;", + "4-(0(0(0"DOT"|1(0|1|2|3|4|5|6|7|8)|3(9|A|B|C|D|E|F)|(4|5|6|7|8|9|A|B|C|D|E|F)"DOT")|(1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"DOT DOT")|(1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"DOT DOT DOT")-C0"DOT DOT DOT DOT DOT DOT); + error += + test_policy6toregex ("E1E1::1;", + "6-"DOT DOT DOT DOT"-E1E10000000000000000000000000001"); + error += + test_policy6toregex ("E1E1:ABCD::1/120;", + "6-"DOT DOT DOT DOT"-E1E1ABCD0000000000000000000000" DOT DOT); + error += + test_policy6toregex ("E1E1:ABCD::ABCD/126;", + "6-"DOT DOT DOT DOT"-E1E1ABCD00000000000000000000ABC(C|D|E|F)"); + error += + test_policy6toregex ("E1E1:ABCD::ABCD/127;", + "6-"DOT DOT DOT DOT"-E1E1ABCD00000000000000000000ABC(C|D)"); + error += + test_policy6toregex ("E1E1:ABCD::ABCD/128:80;", + "6-0050-E1E1ABCD00000000000000000000ABCD"); + return error; +} diff --git a/src/util/test_tun.c b/src/util/test_tun.c new file mode 100644 index 000000000..edbd4c05d --- /dev/null +++ b/src/util/test_tun.c @@ -0,0 +1,72 @@ +/* + This file is part of GNUnet. + Copyright (C) 2010, 2011, 2012 Christian Grothoff + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +/** + * @file tun/test_tun.c + * @brief test for tun.c + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_tun_lib.h" + +static int ret; + +static void +test_udp (size_t pll, + int pl_fill, + uint16_t crc) +{ + struct GNUNET_TUN_IPv4Header ip; + struct GNUNET_TUN_UdpHeader udp; + char payload[pll]; + struct in_addr src; + struct in_addr dst; + + GNUNET_assert (1 == inet_pton (AF_INET, "1.2.3.4", &src)); + GNUNET_assert (1 == inet_pton (AF_INET, "122.2.3.5", &dst)); + memset (payload, pl_fill, sizeof (payload)); + GNUNET_TUN_initialize_ipv4_header (&ip, + IPPROTO_UDP, + pll + sizeof (udp), + &src, + &dst); + udp.source_port = htons (4242); + udp.destination_port = htons (4242); + udp.len = htons (pll); + GNUNET_TUN_calculate_udp4_checksum (&ip, + &udp, + payload, + pll); + if (crc != ntohs (udp.crc)) + { + fprintf (stderr, "Got CRC: %u, wanted: %u\n", + ntohs (udp.crc), + crc); + ret = 1; + } +} + +int main (int argc, + char **argv) +{ + test_udp (4, 3, 22439); + test_udp (4, 1, 23467); + test_udp (7, 17, 6516); + test_udp (12451, 251, 42771); + return ret; +} diff --git a/src/util/tun.c b/src/util/tun.c new file mode 100644 index 000000000..f85f72209 --- /dev/null +++ b/src/util/tun.c @@ -0,0 +1,309 @@ +/* + This file is part of GNUnet. + Copyright (C) 2010, 2011, 2012 Christian Grothoff + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +/** + * @file tun/tun.c + * @brief standard IP calculations for TUN interaction + * @author Philipp Toelke + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_tun_lib.h" + +/** + * IP TTL we use for packets that we assemble (8 bit unsigned integer) + */ +#define FRESH_TTL 64 + + +/** + * Initialize an IPv4 header. + * + * @param ip header to initialize + * @param protocol protocol to use (i.e. IPPROTO_UDP) + * @param payload_length number of bytes of payload that follow (excluding IPv4 header) + * @param src source IP address to use + * @param dst destination IP address to use + */ +void +GNUNET_TUN_initialize_ipv4_header (struct GNUNET_TUN_IPv4Header *ip, + uint8_t protocol, + uint16_t payload_length, + const struct in_addr *src, + const struct in_addr *dst) +{ + GNUNET_assert (20 == sizeof (struct GNUNET_TUN_IPv4Header)); + GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv4Header)); + memset (ip, 0, sizeof (struct GNUNET_TUN_IPv4Header)); + ip->header_length = sizeof (struct GNUNET_TUN_IPv4Header) / 4; + ip->version = 4; + ip->total_length = htons (sizeof (struct GNUNET_TUN_IPv4Header) + payload_length); + ip->identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + 65536); + ip->ttl = FRESH_TTL; + ip->protocol = protocol; + ip->source_address = *src; + ip->destination_address = *dst; + ip->checksum = GNUNET_CRYPTO_crc16_n (ip, sizeof (struct GNUNET_TUN_IPv4Header)); +} + + +/** + * Initialize an IPv6 header. + * + * @param ip header to initialize + * @param protocol protocol to use (i.e. IPPROTO_UDP), technically "next_header" for IPv6 + * @param payload_length number of bytes of payload that follow (excluding IPv6 header) + * @param src source IP address to use + * @param dst destination IP address to use + */ +void +GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip, + uint8_t protocol, + uint16_t payload_length, + const struct in6_addr *src, + const struct in6_addr *dst) +{ + GNUNET_assert (40 == sizeof (struct GNUNET_TUN_IPv6Header)); + GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv6Header)); + memset (ip, 0, sizeof (struct GNUNET_TUN_IPv6Header)); + ip->version = 6; + ip->next_header = protocol; + ip->payload_length = htons ((uint16_t) payload_length); + ip->hop_limit = FRESH_TTL; + ip->destination_address = *dst; + ip->source_address = *src; +} + + +/** + * Calculate IPv4 TCP checksum. + * + * @param ip ipv4 header fully initialized + * @param tcp TCP header (initialized except for CRC) + * @param payload the TCP payload + * @param payload_length number of bytes of TCP payload + */ +void +GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, + struct GNUNET_TUN_TcpHeader *tcp, + const void *payload, + uint16_t payload_length) +{ + uint32_t sum; + uint16_t tmp; + + GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader)); + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_TcpHeader) == + ntohs (ip->total_length)); + GNUNET_assert (IPPROTO_TCP == ip->protocol); + + tcp->crc = 0; + sum = GNUNET_CRYPTO_crc16_step (0, + &ip->source_address, + sizeof (struct in_addr) * 2); + tmp = htons (IPPROTO_TCP); + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t)); + tmp = htons (payload_length + sizeof (struct GNUNET_TUN_TcpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t)); + sum = GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof (struct GNUNET_TUN_TcpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); + tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); +} + + +/** + * Calculate IPv6 TCP checksum. + * + * @param ip ipv6 header fully initialized + * @param tcp header (initialized except for CRC) + * @param payload the TCP payload + * @param payload_length number of bytes of TCP payload + */ +void +GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, + struct GNUNET_TUN_TcpHeader *tcp, + const void *payload, + uint16_t payload_length) +{ + uint32_t sum; + uint32_t tmp; + + GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader)); + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_TcpHeader) == + ntohs (ip->payload_length)); + GNUNET_assert (IPPROTO_TCP == ip->next_header); + tcp->crc = 0; + sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, 2 * sizeof (struct in6_addr)); + tmp = htonl (sizeof (struct GNUNET_TUN_TcpHeader) + payload_length); + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); + tmp = htonl (IPPROTO_TCP); + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); + sum = GNUNET_CRYPTO_crc16_step (sum, tcp, + sizeof (struct GNUNET_TUN_TcpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); + tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); +} + + +/** + * Calculate IPv4 UDP checksum. + * + * @param ip ipv4 header fully initialized + * @param udp UDP header (initialized except for CRC) + * @param payload the UDP payload + * @param payload_length number of bytes of UDP payload + */ +void +GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, + struct GNUNET_TUN_UdpHeader *udp, + const void *payload, + uint16_t payload_length) +{ + uint32_t sum; + uint16_t tmp; + + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader)); + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_UdpHeader) == + ntohs (ip->total_length)); + GNUNET_assert (IPPROTO_UDP == ip->protocol); + + udp->crc = 0; /* technically optional, but we calculate it anyway, just to be sure */ + sum = GNUNET_CRYPTO_crc16_step (0, + &ip->source_address, + sizeof (struct in_addr) * 2); + tmp = htons (IPPROTO_UDP); + sum = GNUNET_CRYPTO_crc16_step (sum, + &tmp, + sizeof (uint16_t)); + tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); + sum = GNUNET_CRYPTO_crc16_step (sum, + &tmp, + sizeof (uint16_t)); + sum = GNUNET_CRYPTO_crc16_step (sum, + udp, + sizeof (struct GNUNET_TUN_UdpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, + payload, + payload_length); + udp->crc = GNUNET_CRYPTO_crc16_finish (sum); +} + + +/** + * Calculate IPv6 UDP checksum. + * + * @param ip ipv6 header fully initialized + * @param udp UDP header (initialized except for CRC) + * @param payload the UDP payload + * @param payload_length number of bytes of UDP payload + */ +void +GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, + struct GNUNET_TUN_UdpHeader *udp, + const void *payload, + uint16_t payload_length) +{ + uint32_t sum; + uint32_t tmp; + + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) == + ntohs (ip->payload_length)); + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) == + ntohs (udp->len)); + GNUNET_assert (IPPROTO_UDP == ip->next_header); + + udp->crc = 0; + sum = GNUNET_CRYPTO_crc16_step (0, + &ip->source_address, + sizeof (struct in6_addr) * 2); + tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); /* aka udp->len */ + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); + tmp = htons (ip->next_header); + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); + sum = GNUNET_CRYPTO_crc16_step (sum, udp, sizeof (struct GNUNET_TUN_UdpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); + udp->crc = GNUNET_CRYPTO_crc16_finish (sum); +} + + +/** + * Calculate ICMP checksum. + * + * @param icmp IMCP header (initialized except for CRC) + * @param payload the ICMP payload + * @param payload_length number of bytes of ICMP payload + */ +void +GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp, + const void *payload, + uint16_t payload_length) +{ + uint32_t sum; + + GNUNET_assert (8 == sizeof (struct GNUNET_TUN_IcmpHeader)); + icmp->crc = 0; + sum = GNUNET_CRYPTO_crc16_step (0, + icmp, + sizeof (struct GNUNET_TUN_IcmpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); + icmp->crc = GNUNET_CRYPTO_crc16_finish (sum); +} + + +/** + * Check if two sockaddrs are equal. + * + * @param sa one address + * @param sb another address + * @param include_port also check ports + * @return #GNUNET_YES if they are equal + */ +int +GNUNET_TUN_sockaddr_cmp (const struct sockaddr *sa, + const struct sockaddr *sb, + int include_port) +{ + if (sa->sa_family != sb->sa_family) + return GNUNET_NO; + + switch (sa->sa_family) + { + case AF_INET: + { + const struct sockaddr_in *sa4 = (const struct sockaddr_in *) sa; + const struct sockaddr_in *sb4 = (const struct sockaddr_in *) sb; + return (sa4->sin_addr.s_addr == sb4->sin_addr.s_addr); + } + case AF_INET6: + { + const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *) sa; + const struct sockaddr_in6 *sb6 = (const struct sockaddr_in6 *) sb; + + return (0 == memcmp(&sa6->sin6_addr, + &sb6->sin6_addr, + sizeof (struct in6_addr))); + } + default: + GNUNET_break (0); + return GNUNET_SYSERR; + } +} + + +/* end of tun.c */ -- cgit v1.2.3