From 80d858ce15b0f77fa259ae7a517053a1aee11447 Mon Sep 17 00:00:00 2001 From: Laurent Ghigonis Date: Sun, 2 Dec 2012 16:14:01 +0100 Subject: add some evdns spikes --- spike/Makefile | 5 ++ spike/evdns.c | 112 +++++++++++++++++++++++++++++++++++++ spike/evdns_chrooted.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 spike/Makefile create mode 100644 spike/evdns.c create mode 100644 spike/evdns_chrooted.c diff --git a/spike/Makefile b/spike/Makefile new file mode 100644 index 0000000..9d07a0a --- /dev/null +++ b/spike/Makefile @@ -0,0 +1,5 @@ +evdns: + $(CC) -o evdns evdns.c -levent + +evdns_chrooted: + $(CC) -o evdns_chrooted evdns_chrooted.c -levent diff --git a/spike/evdns.c b/spike/evdns.c new file mode 100644 index 0000000..852afa0 --- /dev/null +++ b/spike/evdns.c @@ -0,0 +1,112 @@ +#include +#include +#include + +#include + +#include +#include +#include +#include + +int n_pending_requests = 0; +struct event_base *base = NULL; + +struct user_data { + char *name; /* the name we're resolving */ + int idx; /* its position on the command line */ +}; + +void callback(int errcode, struct evutil_addrinfo *addr, void *ptr) +{ + struct user_data *data = ptr; + const char *name = data->name; + if (errcode) { + printf("%d. %s -> %s\n", data->idx, name, evutil_gai_strerror(errcode)); + } else { + struct evutil_addrinfo *ai; + printf("%d. %s", data->idx, name); + if (addr->ai_canonname) + printf(" [%s]", addr->ai_canonname); + puts(""); + for (ai = addr; ai; ai = ai->ai_next) { + char buf[128]; + const char *s = NULL; + if (ai->ai_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr; + s = evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, 128); + } else if (ai->ai_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr; + s = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 128); + } + if (s) + printf(" -> %s\n", s); + } + evutil_freeaddrinfo(addr); + } + free(data->name); + free(data); + if (--n_pending_requests == 0) + event_base_loopexit(base, NULL); +} + +/* Take a list of domain names from the command line and resolve them in + * parallel. */ +int main(int argc, char **argv) +{ + int i; + struct evdns_base *dnsbase; + + if (argc == 1) { + puts("No addresses given."); + return 0; + } + base = event_base_new(); + if (!base) + return 1; + dnsbase = evdns_base_new(base, 1); + if (!dnsbase) + return 2; + + for (i = 1; i < argc; ++i) { + struct evutil_addrinfo hints; + struct evdns_getaddrinfo_request *req; + struct user_data *user_data; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = EVUTIL_AI_CANONNAME; + /* Unless we specify a socktype, we'll get at least two entries for + * each address: one for TCP and one for UDP. That's not what we + * want. */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if (!(user_data = malloc(sizeof(user_data)))) { + perror("malloc"); + exit(1); + } + if (!(user_data->name = strdup(argv[i]))) { + perror("strdup"); + exit(1); + } + user_data->idx = i; + + ++n_pending_requests; + req = evdns_getaddrinfo( + dnsbase, argv[i], NULL /* no service name given */, + &hints, callback, user_data); + if (req == NULL) { + printf(" [request for %s returned immediately]\n", argv[i]); + /* No need to free user_data or decrement n_pending_requests; that + * happened in the callback. */ + } + } + + if (n_pending_requests) + event_base_dispatch(base); + + evdns_base_free(dnsbase, 0); + event_base_free(base); + + return 0; +} diff --git a/spike/evdns_chrooted.c b/spike/evdns_chrooted.c new file mode 100644 index 0000000..edb7ea3 --- /dev/null +++ b/spike/evdns_chrooted.c @@ -0,0 +1,146 @@ +#include +#include +#include + +#include + +#include +#include +#include +#include + +/* for droppriv */ +#include +#include + +int n_pending_requests = 0; +struct event_base *base = NULL; + +struct user_data { + char *name; /* the name we're resolving */ + int idx; /* its position on the command line */ +}; + +void callback(int errcode, struct evutil_addrinfo *addr, void *ptr) +{ + struct user_data *data = ptr; + const char *name = data->name; + if (errcode) { + printf("%d. %s -> %s\n", data->idx, name, evutil_gai_strerror(errcode)); + } else { + struct evutil_addrinfo *ai; + printf("%d. %s", data->idx, name); + if (addr->ai_canonname) + printf(" [%s]", addr->ai_canonname); + puts(""); + for (ai = addr; ai; ai = ai->ai_next) { + char buf[128]; + const char *s = NULL; + if (ai->ai_family == AF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr; + s = evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, 128); + } else if (ai->ai_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr; + s = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 128); + } + if (s) + printf(" -> %s\n", s); + } + evutil_freeaddrinfo(addr); + } + free(data->name); + free(data); + if (--n_pending_requests == 0) + event_base_loopexit(base, NULL); +} + +#define fatal(msg) { printf(msg "\n"); exit(1); } +void +droppriv() +{ + struct passwd *pw; + + /* bad example, never use user 'nobody' in real code, create your own */ + pw = getpwnam("nobody"); + if (!pw) + fatal("unknown user"); + if (chroot(pw->pw_dir) != 0) + fatal("unable to chroot"); + if (chdir("/") != 0) + fatal("unable to chdir"); + if (setgroups(1, &pw->pw_gid) == -1) + fatal("setgroups() failed"); + if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) + fatal("setresgid failed"); + if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) + fatal("setresuid() failed"); + endpwent(); +} + +/* Take a list of domain names from the command line and resolve them in + * parallel. */ +int main(int argc, char **argv) +{ + int i; + struct evdns_base *dnsbase; + + if (argc == 1) { + puts("No addresses given."); + return 0; + } + + if (geteuid() != 0) + errx(1, "need root privileges"); + + droppriv(); + printf("droppriv + chroot DONE\n"); + + base = event_base_new(); + if (!base) + return 1; + dnsbase = evdns_base_new(base, 1); + if (!dnsbase) + return 2; + + for (i = 1; i < argc; ++i) { + struct evutil_addrinfo hints; + struct evdns_getaddrinfo_request *req; + struct user_data *user_data; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = EVUTIL_AI_CANONNAME; + /* Unless we specify a socktype, we'll get at least two entries for + * each address: one for TCP and one for UDP. That's not what we + * want. */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if (!(user_data = malloc(sizeof(user_data)))) { + perror("malloc"); + exit(1); + } + if (!(user_data->name = strdup(argv[i]))) { + perror("strdup"); + exit(1); + } + user_data->idx = i; + + ++n_pending_requests; + req = evdns_getaddrinfo( + dnsbase, argv[i], NULL /* no service name given */, + &hints, callback, user_data); + if (req == NULL) { + printf(" [request for %s returned immediately]\n", argv[i]); + /* No need to free user_data or decrement n_pending_requests; that + * happened in the callback. */ + } + } + + if (n_pending_requests) + event_base_dispatch(base); + + evdns_base_free(dnsbase, 0); + event_base_free(base); + + return 0; +} -- cgit v1.2.3-59-g8ed1b