aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.dir-locals.el8
-rw-r--r--.gitignore33
-rw-r--r--Makefile.am7
-rw-r--r--README47
-rwxr-xr-xautogen.sh66
-rw-r--r--configure.ac62
-rw-r--r--flymake.mk12
-rw-r--r--m4/attributes.m4258
-rw-r--r--src/Makefile.am35
-rw-r--r--src/nss-dontstalkme.c292
-rw-r--r--src/nss-dontstalkme.h0
11 files changed, 820 insertions, 0 deletions
diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000..7c483d2
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,8 @@
+(
+ (c-mode . (
+ (c-file-style . "K&R")
+ (indent-tabs-mode . nil)
+ (c-indent-level . 4)
+ (c-basic-offset . 4)
+ ))
+ )
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..cb54e44
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,33 @@
+aclocal.m4
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+config.rpath
+configure
+compile
+depcomp
+install-sh
+ltmain.sh
+libtool
+missing
+nss-dontstalkme-*.tar.gz
+nss-dontstalkme-*.tar.xz
+Makefile
+Makefile.in
+run
+stamp-*
+TAGS
+*.la
+*.lo
+*.log
+*.o
+*~
+.deps/
+.libs/
+autom4te.cache/
+build-aux/
+m4/libtool*.m4
+m4/lt*.m4
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..15ed2d4
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,7 @@
+SUBDIRS = src
+
+ACLOCAL_AMFLAGS = -I m4
+
+EXTRA_DIST = \
+ flymake.mk \
+ $(NULL)
diff --git a/README b/README
new file mode 100644
index 0000000..d4fc9f6
--- /dev/null
+++ b/README
@@ -0,0 +1,47 @@
+# -*- mode: markdown; -*-
+
+Overview
+--------
+nss-dontstalk me is a nsswitch module that maps host lookups of well known web
+trackers to localhost so they become uneffective.
+
+The idea is to have the same black lists available regardless of the browser/application used.
+
+While doing this via /etc/host would be possible there's no /etc/hosts.d mechanism to
+keep the changes separate. Also maintaining this for ipv4 and ipv6 can be cumbersome.
+
+Compiling
+---------
+nss-dontstalkme uses autotools to build the package:
+
+ ./autogen.sh
+ ./configure --prefix=/usr
+ make
+
+Installation
+------------
+Make sure libnss-dontstalkme.so.2 is in your libraries load path
+either installing it into the filesystem
+
+ make install
+
+or, if you want to run from the built source, by setting LD_LIBRARY_PATH
+
+ LD_LIBRARY_PATH=$PWD/src/.libs
+
+Afterwards add dontstalkme to the hosts entry of /etc/nsswitch.conf e.g. change
+
+ hosts: files myhostname mdns4_minimal [NOTFOUND=return] dns mdns4n
+
+to
+
+ hosts: files myhostname mdns4_minimal [NOTFOUND=return] dontstalkme dns mdns4
+
+It's important to add the `dontstalkme` entry before the `dns` entry.
+
+Testing
+-------
+You can test the basic functionality by running
+
+ LD_LIBRARY_PATH=$PWD/src/.libs/ getent ahostsv4 google-analytics.com
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..d224f31
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+# This file is part of nss-myhostname.
+#
+# Copyright 2008 Lennart Poettering
+#
+# nss-myhostname is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation, either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# nss-myhostname 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with nss-myhostname. If not, If not, see
+# <http://www.gnu.org/licenses/>.
+
+VERSION=1.9
+
+run_versioned() {
+ local P
+ local V
+
+ V=$(echo "$2" | sed -e 's,\.,,g')
+
+ if [ -e "`which $1$V 2> /dev/null`" ] ; then
+ P="$1$V"
+ else
+ if [ -e "`which $1-$2 2> /dev/null`" ] ; then
+ P="$1-$2"
+ else
+ P="$1"
+ fi
+ fi
+
+ shift 2
+ "$P" "$@"
+}
+
+set -ex
+
+if [ "x$1" = "xam" ] ; then
+ run_versioned automake "$VERSION" -a -c --foreign
+ ./config.status
+else
+ rm -rf autom4te.cache
+ rm -f config.cache
+
+ touch config.rpath
+ test "x$LIBTOOLIZE" = "x" && LIBTOOLIZE=libtoolize
+
+ mkdir -p m4
+ "$LIBTOOLIZE" -c --force
+ run_versioned aclocal "$VERSION" -I m4
+ run_versioned autoconf 2.59 -Wall
+ run_versioned autoheader 2.59
+ run_versioned automake "$VERSION" --copy --foreign --add-missing
+
+ if test "x$NOCONFIGURE" = "x"; then
+ CFLAGS="-g -O0" ./configure --sysconfdir=/etc --localstatedir=/var "$@"
+ make clean
+ fi
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..59dd21b
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,62 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+# Copyright 2014 Guido Günther <agx@sigxcpu.org>
+#
+# nss-myhostname is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation, either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# nss-dontstalkme 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with nss-dontstalkme. If not, If not, see
+# <http://www.gnu.org/licenses/>.
+#
+# Based on configure.ac from libnss-myhostname
+
+AC_PREREQ(2.62)
+AC_INIT([nss-dontstalkme],[0.0])
+AC_CONFIG_SRCDIR([src/nss-dontstalkme.c])
+dnl Make automake keep quiet about wildcards & other GNUmake-isms
+AM_INIT_AUTOMAKE([1.11.1 no-dist-gzip dist-xz -Wno-portability])
+AC_CONFIG_HEADERS([config.h])
+AC_SYS_LARGEFILE
+
+AM_PROG_CC_C_O
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+
+# libtool stuff
+AC_DISABLE_STATIC
+LT_PREREQ(2.2)
+LT_INIT
+
+# GCC flags
+DESIRED_FLAGS="-Wall -W -Wextra -pedantic -pipe -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wcast-align -Wwrite-strings -Winline -Wno-unused-parameter -ffast-math -fvisibility=hidden -fdiagnostics-show-option"
+
+for flag in $DESIRED_FLAGS ; do
+ CC_CHECK_CFLAGS([$flag], [CFLAGS="$CFLAGS $flag"])
+done
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([nss.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_CHECK_FUNCS([gethostbyname])
+
+AC_CONFIG_FILES([Makefile src/Makefile])
+
+AC_OUTPUT
diff --git a/flymake.mk b/flymake.mk
new file mode 100644
index 0000000..8228150
--- /dev/null
+++ b/flymake.mk
@@ -0,0 +1,12 @@
+get_cs_flags = $(foreach target,$(subst .,_,$(subst -,_,$($(2)))),$($(target)_$(1)FLAGS))
+get_cs_all_flags = $(foreach type,$(2),$(call get_cs_flags,$(1),$(type)))
+get_cs_compile = $(if $(subst C,,$(1)),$($(1)COMPILE),$(COMPILE))
+get_cs_cmdline = $(call get_cs_compile,$(1)) $(call get_cs_all_flags,$(1),check_PROGRAMS bin_PROGRAMS lib_LTLIBRARIES) -fsyntax-only
+
+check-syntax:
+ s=$(suffix $(CHK_SOURCES));\
+ if [ "$$s" = ".c" ]; then $(call get_cs_cmdline,C) $(CHK_SOURCES);\
+ elif [ "$$s" = ".cpp" ]; then $(call get_cs_cmdline,CXX) $(CHK_SOURCES);\
+ else exit 1; fi
+
+PHONY: check-syntax
diff --git a/m4/attributes.m4 b/m4/attributes.m4
new file mode 100644
index 0000000..9c4a0c8
--- /dev/null
+++ b/m4/attributes.m4
@@ -0,0 +1,258 @@
+dnl Macros to check the presence of generic (non-typed) symbols.
+dnl Copyright (c) 2006-2007 Diego Pettenò <flameeyes@gmail.com>
+dnl Copyright (c) 2006-2007 xine project
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2, or (at your option)
+dnl any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+dnl 02110-1301, USA.
+dnl
+dnl As a special exception, the copyright owners of the
+dnl macro gives unlimited permission to copy, distribute and modify the
+dnl configure scripts that are the output of Autoconf when processing the
+dnl Macro. You need not follow the terms of the GNU General Public
+dnl License when using or distributing such scripts, even though portions
+dnl of the text of the Macro appear in them. The GNU General Public
+dnl License (GPL) does govern all other use of the material that
+dnl constitutes the Autoconf Macro.
+dnl
+dnl This special exception to the GPL applies to versions of the
+dnl Autoconf Macro released by this project. When you make and
+dnl distribute a modified version of the Autoconf Macro, you may extend
+dnl this special exception to the GPL to apply to your modified version as
+dnl well.
+
+AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [
+ AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]),
+ [ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $1"
+ AC_COMPILE_IFELSE([int a;],
+ [eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"],
+ [eval "AS_TR_SH([cc_cv_cflags_$1])='no'"])
+ CFLAGS="$ac_save_CFLAGS"
+ ])
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
+ [$2], [$3])
+])
+
+AC_DEFUN([CC_CHECK_CFLAGS], [
+ AC_CACHE_CHECK([if $CC supports $1 flag],
+ AS_TR_SH([cc_cv_cflags_$1]),
+ CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here!
+ )
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
+ [$2], [$3])
+])
+
+AC_DEFUN([CC_CHECK_LDFLAGS], [
+ AC_CACHE_CHECK([if $CC supports $1 flag],
+ AS_TR_SH([cc_cv_ldflags_$1]),
+ [ac_save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $1"
+ AC_LINK_IFELSE([int main() { return 1; }],
+ [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"],
+ [eval "AS_TR_SH([cc_cv_ldflags_$1])="])
+ LDFLAGS="$ac_save_LDFLAGS"
+ ])
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes],
+ [$2], [$3])
+])
+
+dnl Check for a -Werror flag or equivalent. -Werror is the GCC
+dnl and ICC flag that tells the compiler to treat all the warnings
+dnl as fatal. We usually need this option to make sure that some
+dnl constructs (like attributes) are not simply ignored.
+dnl
+dnl Other compilers don't support -Werror per se, but they support
+dnl an equivalent flag:
+dnl - Sun Studio compiler supports -errwarn=%all
+AC_DEFUN([CC_CHECK_WERROR], [
+ AC_CACHE_CHECK(
+ [for $CC way to treat warnings as errors],
+ [cc_cv_werror],
+ [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror],
+ [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])])
+ ])
+])
+
+AC_DEFUN([CC_CHECK_ATTRIBUTE], [
+ AC_REQUIRE([CC_CHECK_WERROR])
+ AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))],
+ AS_TR_SH([cc_cv_attribute_$1]),
+ [ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $cc_cv_werror"
+ AC_COMPILE_IFELSE([$3],
+ [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"],
+ [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"])
+ CFLAGS="$ac_save_CFLAGS"
+ ])
+
+ AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes],
+ [AC_DEFINE(
+ AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1,
+ [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))]
+ )
+ $4],
+ [$5])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [
+ CC_CHECK_ATTRIBUTE(
+ [constructor],,
+ [void __attribute__((constructor)) ctor() { int a; }],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_FORMAT], [
+ CC_CHECK_ATTRIBUTE(
+ [format], [format(printf, n, n)],
+ [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [
+ CC_CHECK_ATTRIBUTE(
+ [format_arg], [format_arg(printf)],
+ [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [
+ CC_CHECK_ATTRIBUTE(
+ [visibility_$1], [visibility("$1")],
+ [void __attribute__((visibility("$1"))) $1_function() { }],
+ [$2], [$3])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_NONNULL], [
+ CC_CHECK_ATTRIBUTE(
+ [nonnull], [nonnull()],
+ [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_UNUSED], [
+ CC_CHECK_ATTRIBUTE(
+ [unused], ,
+ [void some_function(void *foo, __attribute__((unused)) void *bar);],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [
+ CC_CHECK_ATTRIBUTE(
+ [sentinel], ,
+ [void some_function(void *foo, ...) __attribute__((sentinel));],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [
+ CC_CHECK_ATTRIBUTE(
+ [deprecated], ,
+ [void some_function(void *foo, ...) __attribute__((deprecated));],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_ALIAS], [
+ CC_CHECK_ATTRIBUTE(
+ [alias], [weak, alias],
+ [void other_function(void *foo) { }
+ void some_function(void *foo) __attribute__((weak, alias("other_function")));],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_MALLOC], [
+ CC_CHECK_ATTRIBUTE(
+ [malloc], ,
+ [void * __attribute__((malloc)) my_alloc(int n);],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_PACKED], [
+ CC_CHECK_ATTRIBUTE(
+ [packed], ,
+ [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_CONST], [
+ CC_CHECK_ATTRIBUTE(
+ [const], ,
+ [int __attribute__((const)) twopow(int n) { return 1 << n; } ],
+ [$1], [$2])
+])
+
+AC_DEFUN([CC_FLAG_VISIBILITY], [
+ AC_REQUIRE([CC_CHECK_WERROR])
+ AC_CACHE_CHECK([if $CC supports -fvisibility=hidden],
+ [cc_cv_flag_visibility],
+ [cc_flag_visibility_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $cc_cv_werror"
+ CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden],
+ cc_cv_flag_visibility='yes',
+ cc_cv_flag_visibility='no')
+ CFLAGS="$cc_flag_visibility_save_CFLAGS"])
+
+ AS_IF([test "x$cc_cv_flag_visibility" = "xyes"],
+ [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1,
+ [Define this if the compiler supports the -fvisibility flag])
+ $1],
+ [$2])
+])
+
+AC_DEFUN([CC_FUNC_EXPECT], [
+ AC_REQUIRE([CC_CHECK_WERROR])
+ AC_CACHE_CHECK([if compiler has __builtin_expect function],
+ [cc_cv_func_expect],
+ [ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $cc_cv_werror"
+ AC_COMPILE_IFELSE(
+ [int some_function() {
+ int a = 3;
+ return (int)__builtin_expect(a, 3);
+ }],
+ [cc_cv_func_expect=yes],
+ [cc_cv_func_expect=no])
+ CFLAGS="$ac_save_CFLAGS"
+ ])
+
+ AS_IF([test "x$cc_cv_func_expect" = "xyes"],
+ [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1,
+ [Define this if the compiler supports __builtin_expect() function])
+ $1],
+ [$2])
+])
+
+AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [
+ AC_REQUIRE([CC_CHECK_WERROR])
+ AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported],
+ [cc_cv_attribute_aligned],
+ [ac_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $cc_cv_werror"
+ for cc_attribute_align_try in 64 32 16 8 4 2; do
+ AC_COMPILE_IFELSE([
+ int main() {
+ static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0;
+ return c;
+ }], [cc_cv_attribute_aligned=$cc_attribute_align_try; break])
+ done
+ CFLAGS="$ac_save_CFLAGS"
+ ])
+
+ if test "x$cc_cv_attribute_aligned" != "x"; then
+ AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned],
+ [Define the highest alignment supported])
+ fi
+])
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..840bffc
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,35 @@
+# This file is part of nss-dontstalkme.
+#
+# Copyright 2014 Guido Günther
+#
+# nss-dontstalkme is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation, either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# nss-dontstalkme 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with nss-dontstalkme. If not, If not, see
+# <http://www.gnu.org/licenses/>.
+
+include $(top_srcdir)/flymake.mk
+
+ACLOCAL_AMFLAGS = -I m4
+
+lib_LTLIBRARIES = libnss_dontstalkme.la
+
+AM_CPPFLAGS = -include $(top_builddir)/config.h
+
+libnss_dontstalkme_la_SOURCES = \
+ nss-dontstalkme.c
+
+libnss_dontstalkme_la_LDFLAGS = \
+ -avoid-version \
+ -module \
+ -export-dynamic \
+ -shrext .so.2
+
diff --git a/src/nss-dontstalkme.c b/src/nss-dontstalkme.c
new file mode 100644
index 0000000..39bf34b
--- /dev/null
+++ b/src/nss-dontstalkme.c
@@ -0,0 +1,292 @@
+/*
+ * nss-dontstalkme: Return localhost for tracking host IPs
+ *
+ * Copyright (C) 2014 Guido Günther
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Guido Günther <agx@sigxcpu.org>
+ *
+ * Heavily inspired by nss-myhostname.c which is
+ * Copyright 2008-2011 Lennart Poettering
+ */
+
+#include <assert.h>
+#include <nss.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <errno.h>
+#include <net/if.h>
+
+/* We use 127.0.2.1 as returned address */
+#define LOCALADDRESS_IPV4 (htonl(0x7F000201))
+#define LOCALADDRESS_IPV6 &in6addr_loopback
+#define LOOPBACK_INTERFACE "lo"
+
+#define ALIGN(a) (((a+sizeof(void*)-1)/sizeof(void*))*sizeof(void*))
+#define _public_ __attribute__ ((visibility("default")))
+#define ARRAY_CARDINALITY(Array) (sizeof(Array) / sizeof(*(Array)))
+
+/* The hosts we blacklist */
+const char* stalkers[] = { "www.google-analytics.com",
+ "ssl.google-analytics.com",
+ };
+
+enum nss_status _nss_dontstalkme_gethostbyname4_r(const char *name,
+ struct gaih_addrtuple **pat,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop,
+ int32_t *ttlp) _public_;
+
+enum nss_status _nss_dontstalkme_gethostbyname3_r(const char *name,
+ int af,
+ struct hostent *host,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop,
+ int32_t *ttlp,
+ char **canonp) _public_;
+
+enum nss_status _nss_dontstalkme_gethostbyname2_r(const char *name,
+ int af,
+ struct hostent *host,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop) _public_;
+
+enum nss_status _nss_dontstalkme_gethostbyname_r(const char *name,
+ struct hostent *host,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop) _public_;
+
+
+enum nss_status
+_nss_dontstalkme_gethostbyname4_r(const char *name,
+ struct gaih_addrtuple **pat,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop,
+ int32_t *ttlp)
+{
+ unsigned lo_ifi;
+ size_t l, idx, ms;
+ char *r_name;
+ unsigned int i;
+ struct gaih_addrtuple *r_tuple, *r_tuple_prev = NULL;
+
+ lo_ifi = if_nametoindex(LOOPBACK_INTERFACE);
+
+ for (i = 0; i < ARRAY_CARDINALITY(stalkers); i++) {
+ if (!strcasecmp(stalkers[i], name)) {
+ break;
+ }
+ }
+ if (i == ARRAY_CARDINALITY(stalkers)) {
+ *errnop = ENOENT;
+ *h_errnop = HOST_NOT_FOUND;
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ l = strlen(name);
+ ms = ALIGN(l+1)+ALIGN(sizeof(struct gaih_addrtuple))*2;
+ if (buflen < ms) {
+ *errnop = ENOMEM;
+ *h_errnop = NO_RECOVERY;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ /* First, fill in hostname */
+ r_name = buffer;
+ l = strlen(name);
+ memcpy(r_name, name, l+1);
+ idx = ALIGN(l+1);
+
+ /* Second, fill in IPv6 tuple */
+ r_tuple = (struct gaih_addrtuple*) (buffer + idx);
+ r_tuple->next = r_tuple_prev;
+ r_tuple->name = r_name;
+ r_tuple->family = AF_INET6;
+ memcpy(r_tuple->addr, LOCALADDRESS_IPV6, 16);
+ r_tuple->scopeid = (uint32_t) lo_ifi;
+
+ idx += ALIGN(sizeof(struct gaih_addrtuple));
+ r_tuple_prev = r_tuple;
+
+ /* Third, fill in IPv4 tuple */
+ r_tuple = (struct gaih_addrtuple*) (buffer + idx);
+ r_tuple->next = r_tuple_prev;
+ r_tuple->name = r_name;
+ r_tuple->family = AF_INET;
+ *(uint32_t*) r_tuple->addr = LOCALADDRESS_IPV4;
+ r_tuple->scopeid = (uint32_t) lo_ifi;
+
+ idx += ALIGN(sizeof(struct gaih_addrtuple));
+ r_tuple_prev = r_tuple;
+
+ /* Verify the size matches */
+ assert(idx == ms);
+
+ *pat = r_tuple_prev;
+
+ if (ttlp)
+ *ttlp = 0;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static inline size_t
+proto_address_size(int proto)
+{
+ assert(proto == AF_INET || proto == AF_INET6);
+ return proto == AF_INET6 ? 16 : 4;
+}
+
+static enum nss_status
+fill_in_hostent(const char *hn,
+ int af,
+ struct hostent *result,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop,
+ int32_t *ttlp,
+ char **canonp)
+{
+
+ size_t l, idx, ms;
+ char *r_addr, *r_name, *r_aliases, *r_addr_list;
+ size_t alen;
+
+ alen = proto_address_size(af);
+
+ l = strlen(hn);
+ ms = ALIGN(l+1)+
+ sizeof(char*)+
+ ALIGN(alen)+
+ 2*sizeof(char*);
+
+ if (buflen < ms) {
+ *errnop = ENOMEM;
+ *h_errnop = NO_RECOVERY;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ /* First, fill in hostname */
+ r_name = buffer;
+ memcpy(r_name, hn, l+1);
+ idx = ALIGN(l+1);
+
+ /* Second, create (empty) aliases array */
+ r_aliases = buffer + idx;
+ *(char**) r_aliases = NULL;
+ idx += sizeof(char*);
+
+ /* Third, add addresses */
+ r_addr = buffer + idx;
+ if (af == AF_INET)
+ *(uint32_t*) r_addr = LOCALADDRESS_IPV4;
+ else
+ memcpy(r_addr, LOCALADDRESS_IPV6, 16);
+
+ idx += ALIGN(alen);
+
+ /* Fourth, add address pointer array */
+ r_addr_list = buffer + idx;
+ ((char**) r_addr_list)[0] = r_addr;
+ ((char**) r_addr_list)[1] = NULL;
+ idx += 2*sizeof(char*);
+
+ /* Verify the size matches */
+ assert(idx == ms);
+
+ result->h_name = r_name;
+ result->h_aliases = (char**) r_aliases;
+ result->h_addrtype = af;
+ result->h_length = alen;
+ result->h_addr_list = (char**) r_addr_list;
+
+ if (ttlp)
+ *ttlp = 0;
+
+ if (canonp)
+ *canonp = r_name;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+
+enum nss_status
+_nss_dontstalkme_gethostbyname3_r(const char *name,
+ int af,
+ struct hostent *host,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop,
+ int32_t *ttlp,
+ char **canonp)
+{
+ unsigned int i;
+
+ if (af == AF_UNSPEC)
+ af = AF_INET;
+
+ if (af != AF_INET && af != AF_INET6) {
+ *errnop = EAFNOSUPPORT;
+ *h_errnop = NO_DATA;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ for (i = 0; i < ARRAY_CARDINALITY(stalkers); i++) {
+ if (!strcasecmp(stalkers[i], name)) {
+ break;
+ }
+ }
+ if (i == ARRAY_CARDINALITY(stalkers)) {
+ *errnop = ENOENT;
+ *h_errnop = HOST_NOT_FOUND;
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ return fill_in_hostent(name, af, host, buffer, buflen, errnop, h_errnop, ttlp, canonp);
+}
+
+
+enum nss_status
+_nss_dontstalkme_gethostbyname2_r(const char *name,
+ int af,
+ struct hostent *host,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop)
+{
+ return _nss_dontstalkme_gethostbyname3_r(name,
+ af,
+ host,
+ buffer, buflen,
+ errnop, h_errnop,
+ NULL,
+ NULL);
+}
+
+
+enum nss_status
+ _nss_dontstalkme_gethostbyname_r(const char *name,
+ struct hostent *host,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop)
+{
+ return _nss_dontstalkme_gethostbyname3_r(name,
+ AF_UNSPEC,
+ host,
+ buffer, buflen,
+ errnop, h_errnop,
+ NULL,
+ NULL);
+}
diff --git a/src/nss-dontstalkme.h b/src/nss-dontstalkme.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/nss-dontstalkme.h