diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | README.rst | 15 | ||||
-rw-r--r-- | curlfilter.c | 46 |
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; + } +} |