Skip to content

Instantly share code, notes, and snippets.

@ryancdotorg
Created October 30, 2013 23:20
Show Gist options
  • Save ryancdotorg/7241987 to your computer and use it in GitHub Desktop.
Save ryancdotorg/7241987 to your computer and use it in GitHub Desktop.
Wrapper library to use /dev/null as a service on Linux via LD_PRELOAD
/* This is a wrapper library that will give your server the power of
* /dev/null as a service, as seen at http://devnull-as-a-service.com/
*
* Compile:
* gcc -ggdb -shared -fPIC dnaas.c -ldl -lcurl -o libdnaas.so
*
* Try:
* LD_PRELOAD=./libdnaas.so dd if=/dev/sda of=/dev/null bs=8192 count=16
*
* Install:
* sudo cp libdnaas.so /usr/lib && echo /usr/lib/libdnaas.so | sudo tee -a /etc/ld.so.preload
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <tomcrypt.h>
#include <curl/curl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dlfcn.h>
#ifndef FD_MAX
#define FD_MAX 65536
#endif
#define DEV_NULL_URL "http://devnull-as-a-service.com/dev/null"
static char _dnaas_loaded = 0;
static char _dnaas_devnull[] = "/dev/null";
static FILE * (*_real_fopen)(const char *, const char *);
static FILE * (*_real_freopen)(const char *, const char *, FILE *);
static int (*_real_fclose)(FILE *);
static int (*_real_open)(const char *, int, ...);
static int (*_real_open64)(const char *, int, ...);
static int (*_real_close)(int);
static int (*_real_dup)(int);
static int (*_real_dup2)(int, int);
static int (*_real_dup3)(int, int, int);
static ssize_t (*_real_write)(int, const void *, size_t);
void _dnaas_load();
static char _dnaas_fd_tab[FD_MAX];
void _dnaas_load() {
if (_real_fopen == NULL)
_real_fopen = dlsym(RTLD_NEXT, "fopen");
if (_real_freopen == NULL)
_real_freopen = dlsym(RTLD_NEXT, "freopen");
if (_real_fclose == NULL)
_real_fclose = dlsym(RTLD_NEXT, "fclose");
if (_real_open == NULL)
_real_open = dlsym(RTLD_NEXT, "open");
if (_real_open64 == NULL)
_real_open64 = dlsym(RTLD_NEXT, "open64");
if (_real_close == NULL)
_real_close = dlsym(RTLD_NEXT, "close");
if (_real_dup == NULL)
_real_dup = dlsym(RTLD_NEXT, "dup");
if (_real_dup2 == NULL)
_real_dup2 = dlsym(RTLD_NEXT, "dup2");
if (_real_dup3 == NULL)
_real_dup3 = dlsym(RTLD_NEXT, "dup3");
if (_real_write == NULL)
_real_write = dlsym(RTLD_NEXT, "write");
int i;
for (i = 0; i < FD_MAX; i++)
_dnaas_fd_tab[i] = 0;
_dnaas_loaded = 1; /* curl calls functions we hook, so flip the bit here */
curl_global_init(CURL_GLOBAL_DEFAULT);
}
ssize_t write(int fd, const void *buf, size_t count) {
if (_dnaas_loaded != 1)
_dnaas_load();
if (_dnaas_fd_tab[fd]) {
ssize_t ret = count;
CURL *curl;
CURLcode curl_res;
struct curl_slist *headers=NULL;
//fprintf(stderr, "intercepted write of %d bytes\n", (int)count);
curl = curl_easy_init();
if (!curl) {
fprintf(stderr, "Failed to start curl!\n");
return -1;
}
headers = curl_slist_append(headers, "Expect:");
headers = curl_slist_append(headers, "Content-Type: application/octet-stream");
curl_easy_setopt(curl, CURLOPT_URL, DEV_NULL_URL);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, buf);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, count);
if ((curl_res = curl_easy_perform(curl)) != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(curl_res));
ret = -1;
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return ret;
}
//fprintf(stderr, "write passed through\n");
return _real_write(fd, buf, count);
}
int open(const char *path, int flags, ...) {
va_list args;
mode_t mode;
va_start(args, flags);
mode = va_arg(args, mode_t);
va_end(args);
if (_dnaas_loaded != 1)
_dnaas_load();
int override = 0;
if (strcmp(path, _dnaas_devnull) == 0) {
path = _dnaas_devnull;
override = 1;
}
int fd;
fd = _real_open(path, flags, mode);
_dnaas_fd_tab[fd] = override;
return fd;
}
int open64(const char *path, int flags, ...) {
va_list args;
mode_t mode;
va_start(args, flags);
mode = va_arg(args, mode_t);
va_end(args);
if (_dnaas_loaded != 1)
_dnaas_load();
int override = 0;
if (strcmp(path, _dnaas_devnull) == 0) {
path = _dnaas_devnull;
override = 1;
}
int fd;
fd = _real_open64(path, flags, mode);
_dnaas_fd_tab[fd] = override;
return fd;
}
int close(int fd) {
if (_dnaas_loaded != 1)
_dnaas_load();
_dnaas_fd_tab[fd] = 0;
return _real_close(fd);
}
FILE * fopen(const char *path, const char *mode) {
if (_dnaas_loaded != 1)
_dnaas_load();
int override = 0;
if (strcmp(path, _dnaas_devnull) == 0) {
path = _dnaas_devnull;
override = 1;
}
int fd;
FILE *fstr;
fstr = _real_fopen(path, mode);
fd = fileno(fstr);
_dnaas_fd_tab[fd] = override;
return fstr;
}
FILE * freopen(const char *path, const char *mode, FILE *stream) {
if (_dnaas_loaded != 1)
_dnaas_load();
int override = 0;
if (strcmp(path, _dnaas_devnull) == 0) {
path = _dnaas_devnull;
override = 1;
}
int fd;
FILE *fstr;
fd = fileno(stream);
_dnaas_fd_tab[fd] = 0;
fstr = _real_freopen(path, mode, stream);
fd = fileno(fstr);
_dnaas_fd_tab[fd] = override;
return fstr;
}
int fclose(FILE *stream) {
if (_dnaas_loaded != 1)
_dnaas_load();
int fd;
fd = fileno(stream);
_dnaas_fd_tab[fd] = 0;
return _real_fclose(stream);
}
int dup(int oldfd) {
if (_dnaas_loaded != 1)
_dnaas_load();
int override = _dnaas_fd_tab[oldfd];
_dnaas_fd_tab[oldfd] = 0;
int fd;
if ((fd = _real_dup(oldfd)) >= 0)
_dnaas_fd_tab[fd] = override;
return fd;
}
int dup2(int oldfd, int newfd) {
if (_dnaas_loaded != 1)
_dnaas_load();
int override = _dnaas_fd_tab[oldfd];
_dnaas_fd_tab[oldfd] = 0;
int fd;
if ((fd = _real_dup2(oldfd, newfd)) >= 0)
_dnaas_fd_tab[fd] = override;
return fd;
}
int dup3(int oldfd, int newfd, int flags) {
if (_dnaas_loaded != 1)
_dnaas_load();
int override = _dnaas_fd_tab[oldfd];
_dnaas_fd_tab[oldfd] = 0;
int fd;
if ((fd = _real_dup3(oldfd, newfd, flags)) >= 0)
_dnaas_fd_tab[fd] = override;
return fd;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment