aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--spike/Makefile5
-rw-r--r--spike/evdns.c112
-rw-r--r--spike/evdns_chrooted.c146
3 files changed, 263 insertions, 0 deletions
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 <event2/dns.h>
+#include <event2/util.h>
+#include <event2/event.h>
+
+#include <sys/socket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+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 <event2/dns.h>
+#include <event2/util.h>
+#include <event2/event.h>
+
+#include <sys/socket.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+/* for droppriv */
+#include <unistd.h>
+#include <pwd.h>
+
+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;
+}