Created
October 30, 2013 23:20
-
-
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 file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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