summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Makefile3
-rw-r--r--README.rst15
-rw-r--r--curlfilter.c46
4 files changed, 66 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a7d3377
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*.sw?
+curlfilter.so
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4e1fac1
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,3 @@
+curlfilter.so: curlfilter.c
+ gcc -Wl,-init=init -o $@ -std=c11 -shared -fPIC -ldl -lpcre $<
+
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..9ef00ce
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,15 @@
+curlfilter
+==========
+
+Filter URLs passed to libcurl’s easy interface by regular expression. Can be
+used to implement per-application ad-blocking.
+
+Compile with::
+
+ make
+
+For Spotify run::
+
+ export CURLFILTER_PATTERN="spclient.wg.spotify.com/ad[-s]"
+ LD_PRELOAD=/path/to/curlfilter.so spotify
+
diff --git a/curlfilter.c b/curlfilter.c
new file mode 100644
index 0000000..5984edc
--- /dev/null
+++ b/curlfilter.c
@@ -0,0 +1,46 @@
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <curl/curl.h>
+#include <pcre.h>
+/* the function is actually a macro, which prevents us from redefining it
+ * properly */
+#undef curl_easy_setopt
+
+typedef CURLcode (*orig_curl_easy_setopt) (CURL *handle, CURLoption option, ...);
+
+static pcre *re = NULL;
+
+CURL_EXTERN CURLcode curl_easy_setopt (CURL *handle, CURLoption option, ...) {
+ va_list args;
+ va_start (args, option);
+ void *parameter = va_arg (args, void *);
+
+ if (re != NULL && option == CURLOPT_URL) {
+ int matches[3];
+ if (pcre_exec (re, NULL, parameter, strlen (parameter), 0, 0, matches, 3) >= 0) {
+ /* not allowed */
+ return CURLE_URL_MALFORMAT;
+ }
+ }
+
+ orig_curl_easy_setopt orig_setopt;
+ orig_setopt = (orig_curl_easy_setopt) dlsym (RTLD_NEXT, "curl_easy_setopt");
+ return orig_setopt (handle, option, parameter);
+}
+
+void init () {
+ const char * const pattern = getenv ("CURLFILTER_PATTERN");
+ const char *errmsg = NULL;
+ int errpos;
+ if (pattern == NULL) {
+ fprintf (stderr, "Environment variable CURLFILTER_PATTERN is not set\n");
+ return;
+ }
+ if ((re = pcre_compile (pattern, 0, &errmsg, &errpos, NULL)) == NULL) {
+ fprintf (stderr, "Cannot compile regex %s: %s\n", pattern, errmsg);
+ return;
+ }
+}