src/topology/Makefile
src/transport/Makefile
src/transport/transport.conf
-src/tun/Makefile
src/util/Makefile
src/util/resolver.conf
src/vpn/Makefile
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
$(REST_DIR) \
$(JSONAPI_DIR) \
hello \
- tun \
block \
statistics \
arm \
endif
lib_LTLIBRARIES = \
- libgnunetdnsparser.la \
- libgnunetdnsstub.la \
libgnunetdns.la
libexec_PROGRAMS = \
test_gnunet_dns.sh
endif
-check_PROGRAMS = \
- test_hexcoder
-
gnunet_helper_dns_SOURCES = \
gnunet-helper-dns.c
gnunet_dns_monitor_SOURCES = \
gnunet-dns-monitor.c
gnunet_dns_monitor_LDADD = \
- libgnunetdnsparser.la \
libgnunetdns.la \
$(top_builddir)/src/util/libgnunetutil.la \
$(GN_LIBINTL)
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)
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 = \
$(check_SCRIPTS)
-test_hexcoder_SOURCES = \
- test_hexcoder.c
-test_hexcoder_LDADD = \
- libgnunetdnsparser.la \
- $(top_builddir)/src/util/libgnunetutil.la
+++ /dev/null
-/*
- 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 <http://www.gnu.org/licenses/>.
- */
-
-/**
- * @file dns/dnsparser.c
- * @brief helper library to parse DNS packets.
- * @author Philipp Toelke
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <idna.h>
-#if WINDOWS
-#include <idn-free.h>
-#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;i<n;i++)
- if (GNUNET_OK !=
- GNUNET_DNSPARSER_parse_query (udp_payload,
- udp_payload_length,
- &off,
- &p->queries[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;i<n;i++)
- if (GNUNET_OK !=
- GNUNET_DNSPARSER_parse_record (udp_payload,
- udp_payload_length,
- &off,
- &p->answers[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;i<n;i++)
- if (GNUNET_OK !=
- GNUNET_DNSPARSER_parse_record (udp_payload,
- udp_payload_length,
- &off,
- &p->authority_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;i<n;i++)
- if (GNUNET_OK !=
- GNUNET_DNSPARSER_parse_record (udp_payload,
- udp_payload_length,
- &off,
- &p->additional_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;i<p->num_queries;i++)
- GNUNET_free_non_null (p->queries[i].name);
- GNUNET_free_non_null (p->queries);
- for (i=0;i<p->num_answers;i++)
- GNUNET_DNSPARSER_free_record (&p->answers[i]);
- GNUNET_free_non_null (p->answers);
- for (i=0;i<p->num_authority_records;i++)
- GNUNET_DNSPARSER_free_record (&p->authority_records[i]);
- GNUNET_free_non_null (p->authority_records);
- for (i=0;i<p->num_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;i<p->num_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;i<p->num_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;i<p->num_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;i<p->num_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 */
+++ /dev/null
-/*
- 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 <http://www.gnu.org/licenses/>.
-*/
-/**
- * @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;i<ctx->num_sockets;i++)
- cleanup_rs (&ctx->sockets[i]);
- GNUNET_free (ctx->sockets);
- GNUNET_free (ctx);
-}
-
-
-/* end of dnsstub.c */
+++ /dev/null
-/*
- 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 <http://www.gnu.org/licenses/>.
-*/
-/**
- * @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<len;off++)
- {
- switch (arg[off])
- {
- case '(':
- op++;
- break;
- case ')':
- GNUNET_assert (op > 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;i<len / 2;i++)
- {
- reg = num_to_regex (a[i], m[i]);
- if (NULL == reg)
- {
- GNUNET_free_non_null (ret);
- return NULL;
- }
- if (NULL == ret)
- {
- ret = reg;
- }
- else
- {
- GNUNET_asprintf (&tmp,
- "%s%s",
- ret, reg);
- GNUNET_free (ret);
- GNUNET_free (reg);
- ret = tmp;
- }
- }
- return ret;
-}
-
-
-/**
- * Convert a single line of an IPv4 policy to a regular expression.
- *
- * @param v4 line to convert
- * @return NULL on error
- */
-static char *
-ipv4_to_regex (const struct GNUNET_STRINGS_IPv4NetworkPolicy *v4)
-{
- char *reg;
- char *pp;
- char *ret;
-
- reg = address_to_regex (&v4->network,
- &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 */
+++ /dev/null
-/*
- 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 <http://www.gnu.org/licenses/>.
-*/
-/**
- * @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;
-}
+++ /dev/null
-/*
- 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @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;
-}
+++ /dev/null
-/*
- 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 <http://www.gnu.org/licenses/>.
-*/
-
-/**
- * @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 */
crypto_rsa.c \
disk.c \
disk.h \
+ dnsparser.c \
+ dnsstub.c \
getopt.c \
getopt_helpers.c \
helper.c \
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 = \
$(LIBGCRYPT_LIBS) \
$(LTLIBICONV) \
$(LTLIBINTL) \
- -lltdl $(Z_LIBS) -lunistring $(XLIB)
+ -lltdl -lidn $(Z_LIBS) -lunistring $(XLIB)
libgnunetutil_la_LDFLAGS = \
$(GN_LIB_LDFLAGS) \
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
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
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @file dns/dnsparser.c
+ * @brief helper library to parse DNS packets.
+ * @author Philipp Toelke
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <idna.h>
+#if WINDOWS
+#include <idn-free.h>
+#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;i<n;i++)
+ if (GNUNET_OK !=
+ GNUNET_DNSPARSER_parse_query (udp_payload,
+ udp_payload_length,
+ &off,
+ &p->queries[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;i<n;i++)
+ if (GNUNET_OK !=
+ GNUNET_DNSPARSER_parse_record (udp_payload,
+ udp_payload_length,
+ &off,
+ &p->answers[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;i<n;i++)
+ if (GNUNET_OK !=
+ GNUNET_DNSPARSER_parse_record (udp_payload,
+ udp_payload_length,
+ &off,
+ &p->authority_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;i<n;i++)
+ if (GNUNET_OK !=
+ GNUNET_DNSPARSER_parse_record (udp_payload,
+ udp_payload_length,
+ &off,
+ &p->additional_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;i<p->num_queries;i++)
+ GNUNET_free_non_null (p->queries[i].name);
+ GNUNET_free_non_null (p->queries);
+ for (i=0;i<p->num_answers;i++)
+ GNUNET_DNSPARSER_free_record (&p->answers[i]);
+ GNUNET_free_non_null (p->answers);
+ for (i=0;i<p->num_authority_records;i++)
+ GNUNET_DNSPARSER_free_record (&p->authority_records[i]);
+ GNUNET_free_non_null (p->authority_records);
+ for (i=0;i<p->num_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;i<p->num_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;i<p->num_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;i<p->num_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;i<p->num_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 */
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @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;i<ctx->num_sockets;i++)
+ cleanup_rs (&ctx->sockets[i]);
+ GNUNET_free (ctx->sockets);
+ GNUNET_free (ctx);
+}
+
+
+/* end of dnsstub.c */
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @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<len;off++)
+ {
+ switch (arg[off])
+ {
+ case '(':
+ op++;
+ break;
+ case ')':
+ GNUNET_assert (op > 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;i<len / 2;i++)
+ {
+ reg = num_to_regex (a[i], m[i]);
+ if (NULL == reg)
+ {
+ GNUNET_free_non_null (ret);
+ return NULL;
+ }
+ if (NULL == ret)
+ {
+ ret = reg;
+ }
+ else
+ {
+ GNUNET_asprintf (&tmp,
+ "%s%s",
+ ret, reg);
+ GNUNET_free (ret);
+ GNUNET_free (reg);
+ ret = tmp;
+ }
+ }
+ return ret;
+}
+
+
+/**
+ * Convert a single line of an IPv4 policy to a regular expression.
+ *
+ * @param v4 line to convert
+ * @return NULL on error
+ */
+static char *
+ipv4_to_regex (const struct GNUNET_STRINGS_IPv4NetworkPolicy *v4)
+{
+ char *reg;
+ char *pp;
+ char *ret;
+
+ reg = address_to_regex (&v4->network,
+ &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 */
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @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;
+}
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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;
+}
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @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 */