Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of github.com:msantos/sods

  • Loading branch information...
commit 93660b149c9d41863779afd24093c090037a736b 2 parents b5cf592 + 6027a37
@msantos authored
Showing with 6,035 additions and 0 deletions.
  1. +106 −0 README
  2. +11 −0 ds/Makefile
  3. +299 −0 ds/ds.c
  4. +82 −0 ds/ds.h
  5. +118 −0 ds/iprange.c
  6. +31 −0 ds/iprange.h
  7. +169 −0 sdt/base32.c
  8. +11 −0 sdt/base32.h
  9. +425 −0 sdt/base64.c
  10. +45 −0 sdt/base64.h
  11. +40 −0 sdt/configure
  12. +49 −0 sdt/scripts/sd
  13. +24 −0 sdt/scripts/sdftp
  14. +510 −0 sdt/sdt.c
  15. +207 −0 sdt/sdt.h
  16. +451 −0 sdt/sdt_dns.c
  17. +79 −0 sdt/sdt_err.c
  18. +61 −0 sdt/sdt_rand.c
  19. +56 −0 sdt/sdt_servers.h
  20. +6 −0 seds/Emakefile
  21. +15 −0 seds/Makefile
  22. +56 −0 seds/include/seds.hrl
  23. +2 −0  seds/priv/seds.cfg.dist
  24. +101 −0 seds/src/base32.erl
  25. +185 −0 seds/src/seds.erl
  26. +245 −0 seds/src/seds_protocol.erl
  27. +299 −0 seds/src/seds_proxy.erl
  28. +3 −0  seds/start.sh
  29. +169 −0 sods/base32.c
  30. +11 −0 sods/base32.h
  31. +425 −0 sods/base64.c
  32. +45 −0 sods/base64.h
  33. +39 −0 sods/configure
  34. +224 −0 sods/sods.c
  35. +236 −0 sods/sods.h
  36. +439 −0 sods/sods_dns.c
  37. +22 −0 sods/sods_dns.h
  38. +136 −0 sods/sods_handler.c
  39. +213 −0 sods/sods_io.c
  40. +25 −0 sods/sods_io.h
  41. +89 −0 sods/sods_priv.c
  42. +133 −0 sods/sods_q.c
  43. +23 −0 sods/sods_q.h
  44. +120 −0 sods/sods_sock.c
View
106 README
@@ -0,0 +1,106 @@
+
+WHAT IS IT?
+
+sods is a socket over dns server that uses the DNS to tunnel data. sods
+includes a small, portable client (sdt) and ds, a utility to scan for
+DNS servers that support recursion.
+
+The protocol is interoperable with OzymanDNS
+(http://lmgtfy.com/?q=OzymanDNS).
+
+
+WHAT DO I NEED TO BUILD IT?
+
+Not much. OpenSSL is optional, if your OS doesn't support
+arc4random().
+
+sods has been built on Ubuntu Linux, Maemo, OpenWRT, Mac OS X and
+Solaris 8.
+
+
+HOW DO I BUILD IT?
+
+# Server
+cd sods
+./configure
+# adjust the Makefile
+make
+
+# Client
+cd sdt
+./configure
+# adjust the Makefile
+make
+
+
+HOW DO I RUN IT?
+
+# In the sods directory
+sudo ./sods -vvvv -d /tmp -L 127.0.0.1:22 a.example.com # if you have an SSH server on localhost
+
+# In the sdt directory
+ssh -o ProxyCommand="./sdt -r 127.0.0.1 sshdns.a.example.com" 127.0.0.100
+
+# As a TCP proxy
+./sdt p 23233 -r 127.0.0.1 sshdns.a.example.com
+ssh -p 23233 localhost # for OpenSSH
+
+The sods client works best with GNU screen installed on your shell
+server (see the scripts directory for an example of a script to
+reconnect if the connection is dropped).
+
+
+WHY WOULD I WANT TO USE IT?
+
+sods is tiny, easily ported and fast. Well, sort of fast, for a
+tunnel going over DNS. Which means not really very fast.
+
+sods has a few tricks to get around network limitations.
+
+Some ways to use sods:
+
+* use of gated internet access that allow DNS queries, like those found
+in airports, coffee shops, restaurants and hotels, when you just need
+quick SSH access
+
+* to bypass firewall port or proxy filtering and snooping
+
+* penetration testing: bypass strict access controls on outgoing
+connections on secure networks
+
+* have fun with anyone doing traffic analysis on your network usage
+
+
+FEATURES
+
+* use TXT, CNAME or NULL records to encapsulate data
+
+* supports multiple forwarded sessions (use multiple "-L" option)
+
+* round robin packets between name servers
+
+* bounce connections off of public recursive name servers (-r random)
+
+* dynamic backoff/throttling of client
+
+* client can use be used as a pipe (for OpenSSH) or as a TCP proxy (for other ssh clients)
+
+
+TODO
+
+* remove hardcoded options and use define, e.g., nobody/nogroup
+
+* re-write the sods server in Erlang, using the native SSH
+support. Reliable, fault tolerant DNS and ssh server for an unreliable
+protocol!!
+
+* write an Erlang client
+
+* multiplex connections to the TCP proxy
+
+* allow the client to specify a host/port
+
+For example, if the client requests "mysshserver.com.sshdns.s.example.com",
+the request would cause the sods server to open a port to
+"mysshserver.com" on port 22. To specify a port, the client could
+embed the port, maybe: mysshserver.com-2222.sshdns.s.example.com
View
11 ds/Makefile
@@ -0,0 +1,11 @@
+CC=gcc
+RM=rm
+
+#LIB=/usr/lib/libresolv.a
+LIB=-lresolv
+
+all:
+ $(CC) -g -Wall -o ds ds.c iprange.c $(LIB)
+
+clean:
+ -@$(RM) ds *.o
View
299 ds/ds.c
@@ -0,0 +1,299 @@
+/*
+ * Scan IP ranges for DNS servers and for servers
+ * supporting recursion.
+ *
+ * Copyright (c) 2009 Michael Santos <michael.santos@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "ds.h"
+#include "iprange.h"
+
+#define HOSTNAME "www.example.com"
+
+extern char *__progname;
+
+typedef struct _DS_STATE {
+ in_addr_t first; /* host endian */
+ in_addr_t last; /* host endian */
+ struct {
+ in_port_t remote;
+ in_port_t local;
+ } port;
+ int s;
+ struct sockaddr_in sa;
+ struct sockaddr_in lo;
+ char *queryhost;
+ int verbose;
+} DS_STATE;
+
+/* bit 0: message is a response
+ * bit 7: recursion desired
+ * bit 8: recursion available
+ * bit 12, 13, 14, 15: reply code
+ * 2 = SERVFAIL
+ * 5 = REFUSED
+ *
+ * 1000 0000 1000 0001
+ * 1... .... .... .... = response
+ * .000 0... .... .... = standard query
+ * .... ...0 .... .... = recursion not requested
+ * .... .... 1... .... = recursion available
+ * .... .... .... ...1 = authoritative answer not found
+ *
+ * 0001 0100 0000 1001
+ * 0... .... .... .... = not a response
+ * .001 0... .... .... = ???
+ * .... ...0 .... .... = recursion not requested
+ * .... .... 0... .... = recursion not available
+ * .... .... .... 1001 = 9 ???
+ *
+ * 1000 0000 1000 0001
+ * 1... .... .... .... = response
+ * .000 0... .... .... = ???
+ * .... ...0 .... .... = recursion not requested
+ * .... .... 1... .... = recursion available
+ * .... .... .... ...1 = not authoritative
+ *
+ * 0000 0000 1000 0001
+ * .... .... 1... .... = recursion available
+ * .... .... .... ...1 = not authoritative
+ *
+ * 1000 0001 0000 0000
+ * 1... .... .... .... = response
+ * .000 0... .... .... = standard query
+ * .... ...1 .... .... = recursion requested
+ * .... .... 0... .... = recursion not available
+ * .... .... .... .... = no error
+ */
+
+struct dns_header {
+ u_int16_t dns_id;
+ u_int16_t dns_flags;
+ u_int16_t dns_no_questions;
+ u_int16_t dns_no_answers;
+ u_int16_t dns_no_authority;
+ u_int16_t dns_no_additional;
+};
+
+struct dns_answer {
+ u_int16_t dns_name;
+ u_int16_t dns_type;
+ u_int16_t dns_class;
+ u_int16_t dns_time_to_live;
+ u_int16_t dns_time_to_live2;
+ u_int16_t dns_data_len;
+};
+
+
+void ds_reader(DS_STATE *ds);
+void ds_writer(DS_STATE *ds);
+void wakeup(int sig);
+void usage(DS_STATE *ds);
+
+int woken = 0;
+
+ int
+main (int argc, char *argv[])
+{
+ DS_STATE *ds = NULL;
+ pid_t pid = 0;
+
+ int ch = 0;
+
+ IS_NULL(ds = (DS_STATE *)calloc(1, sizeof(DS_STATE)));
+
+ ds->queryhost = HOSTNAME;
+ ds->port.remote = 53;
+ ds->port.local = 53535;
+
+ while ( (ch = getopt(argc, argv, "H:hl:p:v")) != -1) {
+ switch (ch) {
+ case 'H':
+ ds->queryhost = optarg;
+ break;
+ case 'l':
+ ds->port.local = (in_port_t)atoi(optarg);
+ break;
+ case 'p':
+ ds->port.remote = (in_port_t)atoi(optarg);
+ break;
+ case 'v':
+ ds->verbose++;
+ break;
+ case 'h':
+ default:
+ usage(ds);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ usage(ds);
+
+ if (parseip(argv[0], &ds->first, &ds->last) < 0)
+ errx(EXIT_FAILURE, "Invalid address: %s", argv[0]);
+
+ if (ds->last - ds->first > 2) {
+ ds->last--;
+ ds->first++;
+ }
+
+ if ( (ds->s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ err(EXIT_FAILURE, "socket");
+
+ (void)memset(&ds->sa, 0, sizeof(struct sockaddr_in));
+ ds->sa.sin_family = AF_INET;
+ ds->sa.sin_port = htons(ds->port.remote);
+
+ (void)memset(&ds->lo, 0, sizeof(struct sockaddr_in));
+ ds->lo.sin_family = AF_INET;
+ ds->lo.sin_addr.s_addr = INADDR_ANY;
+ ds->lo.sin_port = htons(ds->port.local);
+
+ IS_ERR(bind(ds->s, (struct sockaddr *)&ds->lo, sizeof(ds->lo)));
+
+ switch ( (pid = fork())) {
+ case -1:
+ err(EXIT_FAILURE, "fork");
+ case 0: /* child */
+ ds_reader(ds);
+ break;
+ default:
+ (void)signal(SIGCHLD, wakeup);
+ ds_writer(ds);
+ sleep (5);
+ (void)kill(SIGTERM, pid);
+ wait(NULL);
+ break;
+ }
+
+ exit (EXIT_SUCCESS);
+}
+
+ void
+ds_writer(DS_STATE *ds)
+{
+ u_char *buf = NULL;
+ in_addr_t ip = 0;
+
+ struct in_addr ia;
+
+ IS_NULL(buf = (u_char *)calloc(1, NS_PACKETSZ));
+
+ if (res_mkquery(ns_o_query, HOSTNAME, ns_c_in, ns_t_a, NULL, 0, NULL, buf, NS_PACKETSZ) < 0)
+ errx(EXIT_FAILURE, "%s", hstrerror(h_errno));
+
+ for (ip = ds->first; ip <= ds->last; ip++) {
+ if (ds->verbose > 1) {
+ ia.s_addr = ntohl(ip);
+ (void)fprintf(stderr, "Sending: %s\n", inet_ntoa(ia));
+ }
+
+ ds->sa.sin_addr.s_addr = htonl(ip);
+ if (sendto(ds->s, buf, NS_PACKETSZ, 0, (struct sockaddr *)&ds->sa, sizeof(ds->sa)) < 0)
+ err(EXIT_FAILURE, "sendto");
+ }
+}
+
+ void
+ds_reader(DS_STATE *ds)
+{
+ u_char *buf = NULL;
+ socklen_t len = 0;
+
+ struct sockaddr_in sa;
+ struct dns_header hdr;
+ char *status = NULL;
+ char *rerr = NULL;
+
+ IS_NULL(buf = (u_char *)calloc(1, NS_PACKETSZ));
+
+ for ( ; ; ) {
+ if (woken > 0) return;
+
+ len = sizeof(sa);
+ if (recvfrom(ds->s, buf, NS_PACKETSZ, 0, (struct sockaddr *)&sa, &len) < 0)
+ warn("recvfrom");
+
+ (void)memcpy(&hdr, buf, sizeof(hdr));
+
+ hdr.dns_flags = ntohs(hdr.dns_flags);
+ hdr.dns_id = ntohs(hdr.dns_id);
+
+ /* 1000 0000 0000 0000 = 0x8000 (response) */
+ /* 0000 0000 1000 0000 = 0x80 (recursion available) */
+ if ( (hdr.dns_flags & 0x8000) == 0) {
+ warnx("not a response packet: %s:%d = %u\n", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port), hdr.dns_flags);
+ continue;
+ }
+
+ status = "UNKNOWN";
+ rerr = "UNKNOWN";
+
+ if (hdr.dns_flags & 0x80)
+ status = "RECURSE";
+ else {
+ if (ds->verbose == 0)
+ continue;
+ status = "LOCALONLY";
+ }
+
+ if ( (hdr.dns_flags & 0x000F) == 0)
+ rerr = "NOERR";
+ else if (hdr.dns_flags & 0x0001)
+ rerr = "NOT AUTHORITATIVE";
+ else if (hdr.dns_flags & 0x0002)
+ rerr = "SERVFAIL";
+ else if (hdr.dns_flags & 0x0005)
+ rerr = "REFUSED";
+
+ if (ds->verbose > 1)
+ (void)printf("Response: %s = %s/%s (%x) [%x]\n", inet_ntoa(sa.sin_addr),
+ status, rerr, hdr.dns_flags, hdr.dns_id);
+ else
+ (void)printf("%s = %s\n", inet_ntoa(sa.sin_addr), rerr);
+ }
+}
+
+ void
+wakeup (int sig)
+{
+ switch (sig) {
+ case SIGCHLD:
+ woken = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+void
+usage(DS_STATE *ds)
+{
+ (void)fprintf(stderr, "%s: [-H|-h|-p|-l]\n", __progname);
+ exit (EXIT_FAILURE);
+}
View
82 ds/ds.h
@@ -0,0 +1,82 @@
+/*
+ * Scan IP ranges for DNS servers and for servers
+ * supporting recursion.
+ *
+ * Copyright (c) 2009 Michael Santos <michael.santos@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include <signal.h>
+#include <netdb.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <sys/wait.h>
+
+#define DS_VERSION "0.01"
+
+#define IS_ERR(x) do { \
+ if ((x) == -1) { \
+ err(EXIT_FAILURE, "%s", #x); \
+ } \
+} while (0)
+
+#define IS_NULL(x) do { \
+ if ((x) == NULL) { \
+ err(EXIT_FAILURE, "%s", #x); \
+ } \
+} while (0)
+
+#define TIMESTAMP() do { \
+ char outstr[200]; \
+ time_t t; \
+ struct tm *tmp; \
+ \
+ t = time(NULL); \
+ tmp = localtime(&t); \
+ if (tmp == NULL) { \
+ perror("localtime"); \
+ exit(EXIT_FAILURE); \
+ } \
+ \
+ if (strftime(outstr, sizeof(outstr), "%Y-%m-%d %H:%M:%S ", tmp) == 0) { \
+ (void)fprintf(stderr, "strftime returned 0"); \
+ exit(EXIT_FAILURE); \
+ } \
+ \
+ (void)fprintf(stderr, "%s", outstr); \
+} while (0)
+
+
+#define VERBOSE(x, ...) do { \
+ if (ss->verbose >= 4) { \
+ TIMESTAMP(); \
+ } \
+ if (ss->verbose >= x) { \
+ (void)fprintf (stderr, __VA_ARGS__); \
+ } \
+} while (0)
+
View
118 ds/iprange.c
@@ -0,0 +1,118 @@
+/*
+ * Scan IP ranges for DNS servers and for servers
+ * supporting recursion.
+ *
+ * Copyright (c) 2009 Michael Santos <michael.santos@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * Parse an IP address and return a range.
+ */
+#include "iprange.h"
+
+in_addr_t quad2hl(char *buf);
+in_addr_t mask2hl(char *buf);
+
+ int
+parseip (char *buf, in_addr_t *network, in_addr_t *broadcast)
+{
+ char *ip = NULL;
+ char *mask = NULL;
+ char *p = NULL;
+
+ in_addr_t addr = 0;
+ in_addr_t netmask = 0;
+
+ if ( (ip = strdup(buf)) == NULL)
+ err(EXIT_FAILURE, "strdup");
+
+ p = strchr(ip, '/');
+ if (p == NULL)
+ mask = "32";
+ else {
+ *p++ = '\0';
+ mask = p;
+ }
+
+ /* Determine the base IP address */
+ if ( (addr = quad2hl(ip)) == 0) {
+ warnx("Invalid IP address: %s", ip);
+ return (-1);
+ }
+
+ /* Get the mask */
+ if ( (netmask = mask2hl(mask)) == 0)
+ netmask = quad2hl(mask);
+
+ if (netmask == 0) {
+ warnx("Invalid netmask: %s", mask);
+ return (-1);
+ }
+
+ *network = addr & netmask;
+ *broadcast = addr | ~netmask;
+
+ return (0);
+}
+
+ in_addr_t
+quad2hl(char *buf)
+{
+ in_addr_t addr = 0;
+ u_int32_t byte[4];
+ int i = 0;
+
+ if (buf == NULL)
+ return (0);
+
+ if (sscanf(buf, "%u.%u.%u.%u", &byte[0], &byte[1],
+ &byte[2], &byte[3]) != 4)
+ return (0);
+
+ for (i = 0; i < 4; i++)
+ if (byte[i] > 255)
+ return (0);
+
+ for (i = 0; i < 4; i++)
+ addr += byte[i] << (24 - i * 8);
+
+ return (addr);
+}
+
+ in_addr_t
+mask2hl(char *buf)
+{
+ u_int32_t byte;
+ in_addr_t mask = 0;
+
+ if (buf == NULL)
+ return (0);
+
+ if (sscanf(buf, "%u", &byte) != 1)
+ return (0);
+
+ if (byte > 32 || byte == 0)
+ return (0);
+
+ while (byte > 0) {
+ mask = (mask >> 1) + 0x80000000;
+ byte--;
+ }
+
+ return (mask);
+}
+
View
31 ds/iprange.h
@@ -0,0 +1,31 @@
+/*
+ * Scan IP ranges for DNS servers and for servers
+ * supporting recursion.
+ *
+ * Copyright (c) 2009 Michael Santos <michael.santos@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+int parseip (char *buf, in_addr_t *network, in_addr_t *broadcast);
+
View
169 sdt/base32.c
@@ -0,0 +1,169 @@
+/* (PD) 2001 The Bitzi Corporation
+ * Please see file COPYING or http://bitzi.com/publicdomain
+ * for more info.
+ *
+ * $Id: base32.c,v 1.1.1.1 2008-02-24 12:28:23 user Exp $
+ *
+ * Modified by Martin Hedenfalk 2005 for use in ShakesPeer.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BASE32_LOOKUP_MAX 43
+static char *base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+static unsigned char base32Lookup[BASE32_LOOKUP_MAX][2] =
+{
+ { '0', 0xFF },
+ { '1', 0xFF },
+ { '2', 0x1A },
+ { '3', 0x1B },
+ { '4', 0x1C },
+ { '5', 0x1D },
+ { '6', 0x1E },
+ { '7', 0x1F },
+ { '8', 0xFF },
+ { '9', 0xFF },
+ { ':', 0xFF },
+ { ';', 0xFF },
+ { '<', 0xFF },
+ { '=', 0xFF },
+ { '>', 0xFF },
+ { '?', 0xFF },
+ { '@', 0xFF },
+ { 'A', 0x00 },
+ { 'B', 0x01 },
+ { 'C', 0x02 },
+ { 'D', 0x03 },
+ { 'E', 0x04 },
+ { 'F', 0x05 },
+ { 'G', 0x06 },
+ { 'H', 0x07 },
+ { 'I', 0x08 },
+ { 'J', 0x09 },
+ { 'K', 0x0A },
+ { 'L', 0x0B },
+ { 'M', 0x0C },
+ { 'N', 0x0D },
+ { 'O', 0x0E },
+ { 'P', 0x0F },
+ { 'Q', 0x10 },
+ { 'R', 0x11 },
+ { 'S', 0x12 },
+ { 'T', 0x13 },
+ { 'U', 0x14 },
+ { 'V', 0x15 },
+ { 'W', 0x16 },
+ { 'X', 0x17 },
+ { 'Y', 0x18 },
+ { 'Z', 0x19 }
+};
+
+int base32_encode_length(int rawLength)
+{
+ return ((rawLength * 8) / 5) + ((rawLength % 5) != 0) + 1;
+}
+
+int base32_decode_length(int base32Length)
+{
+ return ((base32Length * 5) / 8);
+}
+
+void base32_encode_into(const void *_buffer, unsigned int bufLen, char *base32Buffer)
+{
+ unsigned int i, index;
+ unsigned char word;
+ const unsigned char *buffer = _buffer;
+
+ for(i = 0, index = 0; i < bufLen;)
+ {
+ /* Is the current word going to span a byte boundary? */
+ if (index > 3)
+ {
+ word = (buffer[i] & (0xFF >> index));
+ index = (index + 5) % 8;
+ word <<= index;
+ if (i < bufLen - 1)
+ word |= buffer[i + 1] >> (8 - index);
+
+ i++;
+ }
+ else
+ {
+ word = (buffer[i] >> (8 - (index + 5))) & 0x1F;
+ index = (index + 5) % 8;
+ if (index == 0)
+ i++;
+ }
+
+ assert(word < 32);
+ *(base32Buffer++) = (char)base32Chars[word];
+ }
+
+ *base32Buffer = 0;
+}
+
+char *base32_encode(const void *buf, unsigned int len)
+{
+ char *tmp = malloc(base32_encode_length(len));
+ base32_encode_into(buf, len, tmp);
+ return tmp;
+}
+
+int base32_decode_into(const char *base32Buffer, unsigned int base32BufLen, void *_buffer)
+{
+ int i, index, max, lookup, offset;
+ unsigned char word;
+ unsigned char *buffer = _buffer;
+
+ memset(buffer, 0, base32_decode_length(base32BufLen));
+ max = strlen(base32Buffer);
+ for(i = 0, index = 0, offset = 0; i < max; i++)
+ {
+ lookup = toupper(base32Buffer[i]) - '0';
+ /* Check to make sure that the given word falls inside
+ a valid range */
+ if ( lookup < 0 && lookup >= BASE32_LOOKUP_MAX)
+ word = 0xFF;
+ else
+ word = base32Lookup[lookup][1];
+
+ /* If this word is not in the table, ignore it */
+ if (word == 0xFF)
+ continue;
+
+ if (index <= 3)
+ {
+ index = (index + 5) % 8;
+ if (index == 0)
+ {
+ buffer[offset] |= word;
+ offset++;
+ }
+ else
+ buffer[offset] |= word << (8 - index);
+ }
+ else
+ {
+ index = (index + 5) % 8;
+ buffer[offset] |= (word >> index);
+ offset++;
+
+ buffer[offset] |= word << (8 - index);
+ }
+ }
+ return offset;
+}
+
+void *base32_decode(const char *buf, unsigned int *outlen)
+{
+ unsigned int len = strlen(buf);
+ char *tmp = malloc(base32_decode_length(len));
+ unsigned int x = base32_decode_into(buf, len, tmp);
+ if(outlen)
+ *outlen = x;
+ return tmp;
+}
+
View
11 sdt/base32.h
@@ -0,0 +1,11 @@
+
+#ifndef _b32_h_
+#define _b32_h_
+
+int base32_encode_length(int rawLength);
+int base32_decode_length(int base32Length);
+void base32_encode_into(const void *_buffer, unsigned int bufLen, char *base32Buffer);
+char *base32_encode(const void *buf, unsigned int len);
+int base32_decode_into(const char *base32Buffer, unsigned int base32BufLen, void *_buffer);
+void *base32_decode(const char *buf, unsigned int *outlen);
+#endif
View
425 sdt/base64.c
@@ -0,0 +1,425 @@
+/* base64.c -- Encode binary data using printable characters.
+ Copyright (C) 1999, 2000, 2001, 2004, 2005, 2006 Free Software
+ Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/* Written by Simon Josefsson. Partially adapted from GNU MailUtils
+ * (mailbox/filter_trans.c, as of 2004-11-28). Improved by review
+ * from Paul Eggert, Bruno Haible, and Stepan Kasal.
+ *
+ * See also RFC 3548 <http://www.ietf.org/rfc/rfc3548.txt>.
+ *
+ * Be careful with error checking. Here is how you would typically
+ * use these functions:
+ *
+ * bool ok = base64_decode_alloc (in, inlen, &out, &outlen);
+ * if (!ok)
+ * FAIL: input was not valid base64
+ * if (out == NULL)
+ * FAIL: memory allocation error
+ * OK: data in OUT/OUTLEN
+ *
+ * size_t outlen = base64_encode_alloc (in, inlen, &out);
+ * if (out == NULL && outlen == 0 && inlen != 0)
+ * FAIL: input too long
+ * if (out == NULL)
+ * FAIL: memory allocation error
+ * OK: data in OUT/OUTLEN.
+ *
+ */
+
+/* #include <config.h> */
+
+/* Get prototype. */
+#include "base64.h"
+
+/* Get malloc. */
+#include <stdlib.h>
+
+/* Get UCHAR_MAX. */
+#include <limits.h>
+
+/* C89 compliant way to cast 'char' to 'unsigned char'. */
+static inline unsigned char
+to_uchar (char ch)
+{
+ return ch;
+}
+
+/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
+ If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as
+ possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero
+ terminate the output buffer. */
+void
+base64_encode (const char * /* restrict */ in, size_t inlen,
+ char * /* restrict */ out, size_t outlen)
+{
+ static const char b64str[64] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ while (inlen && outlen)
+ {
+ *out++ = b64str[(to_uchar (in[0]) >> 2) & 0x3f];
+ if (!--outlen)
+ break;
+ *out++ = b64str[((to_uchar (in[0]) << 4)
+ + (--inlen ? to_uchar (in[1]) >> 4 : 0))
+ & 0x3f];
+ if (!--outlen)
+ break;
+ *out++ =
+ (inlen
+ ? b64str[((to_uchar (in[1]) << 2)
+ + (--inlen ? to_uchar (in[2]) >> 6 : 0))
+ & 0x3f]
+ : '=');
+ if (!--outlen)
+ break;
+ *out++ = inlen ? b64str[to_uchar (in[2]) & 0x3f] : '=';
+ if (!--outlen)
+ break;
+ if (inlen)
+ inlen--;
+ if (inlen)
+ in += 3;
+ }
+
+ if (outlen)
+ *out = '\0';
+}
+
+/* Allocate a buffer and store zero terminated base64 encoded data
+ from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e.,
+ the length of the encoded data, excluding the terminating zero. On
+ return, the OUT variable will hold a pointer to newly allocated
+ memory that must be deallocated by the caller. If output string
+ length would overflow, 0 is returned and OUT is set to NULL. If
+ memory allocation failed, OUT is set to NULL, and the return value
+ indicates length of the requested memory block, i.e.,
+ BASE64_LENGTH(inlen) + 1. */
+size_t
+base64_encode_alloc (const char *in, size_t inlen, char **out)
+{
+ size_t outlen = 1 + BASE64_LENGTH (inlen);
+
+ /* Check for overflow in outlen computation.
+ *
+ * If there is no overflow, outlen >= inlen.
+ *
+ * If the operation (inlen + 2) overflows then it yields at most +1, so
+ * outlen is 0.
+ *
+ * If the multiplication overflows, we lose at least half of the
+ * correct value, so the result is < ((inlen + 2) / 3) * 2, which is
+ * less than (inlen + 2) * 0.66667, which is less than inlen as soon as
+ * (inlen > 4).
+ */
+ if (inlen > outlen)
+ {
+ *out = NULL;
+ return 0;
+ }
+
+ *out = malloc (outlen);
+ if (!*out)
+ return outlen;
+
+ base64_encode (in, inlen, *out, outlen);
+
+ return outlen - 1;
+}
+
+/* With this approach this file works independent of the charset used
+ (think EBCDIC). However, it does assume that the characters in the
+ Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255. POSIX
+ 1003.1-2001 require that char and unsigned char are 8-bit
+ quantities, though, taking care of that problem. But this may be a
+ potential problem on non-POSIX C99 platforms.
+
+ IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_"
+ as the formal parameter rather than "x". */
+#define B64(_) \
+ ((_) == 'A' ? 0 \
+ : (_) == 'B' ? 1 \
+ : (_) == 'C' ? 2 \
+ : (_) == 'D' ? 3 \
+ : (_) == 'E' ? 4 \
+ : (_) == 'F' ? 5 \
+ : (_) == 'G' ? 6 \
+ : (_) == 'H' ? 7 \
+ : (_) == 'I' ? 8 \
+ : (_) == 'J' ? 9 \
+ : (_) == 'K' ? 10 \
+ : (_) == 'L' ? 11 \
+ : (_) == 'M' ? 12 \
+ : (_) == 'N' ? 13 \
+ : (_) == 'O' ? 14 \
+ : (_) == 'P' ? 15 \
+ : (_) == 'Q' ? 16 \
+ : (_) == 'R' ? 17 \
+ : (_) == 'S' ? 18 \
+ : (_) == 'T' ? 19 \
+ : (_) == 'U' ? 20 \
+ : (_) == 'V' ? 21 \
+ : (_) == 'W' ? 22 \
+ : (_) == 'X' ? 23 \
+ : (_) == 'Y' ? 24 \
+ : (_) == 'Z' ? 25 \
+ : (_) == 'a' ? 26 \
+ : (_) == 'b' ? 27 \
+ : (_) == 'c' ? 28 \
+ : (_) == 'd' ? 29 \
+ : (_) == 'e' ? 30 \
+ : (_) == 'f' ? 31 \
+ : (_) == 'g' ? 32 \
+ : (_) == 'h' ? 33 \
+ : (_) == 'i' ? 34 \
+ : (_) == 'j' ? 35 \
+ : (_) == 'k' ? 36 \
+ : (_) == 'l' ? 37 \
+ : (_) == 'm' ? 38 \
+ : (_) == 'n' ? 39 \
+ : (_) == 'o' ? 40 \
+ : (_) == 'p' ? 41 \
+ : (_) == 'q' ? 42 \
+ : (_) == 'r' ? 43 \
+ : (_) == 's' ? 44 \
+ : (_) == 't' ? 45 \
+ : (_) == 'u' ? 46 \
+ : (_) == 'v' ? 47 \
+ : (_) == 'w' ? 48 \
+ : (_) == 'x' ? 49 \
+ : (_) == 'y' ? 50 \
+ : (_) == 'z' ? 51 \
+ : (_) == '0' ? 52 \
+ : (_) == '1' ? 53 \
+ : (_) == '2' ? 54 \
+ : (_) == '3' ? 55 \
+ : (_) == '4' ? 56 \
+ : (_) == '5' ? 57 \
+ : (_) == '6' ? 58 \
+ : (_) == '7' ? 59 \
+ : (_) == '8' ? 60 \
+ : (_) == '9' ? 61 \
+ : (_) == '+' ? 62 \
+ : (_) == '/' ? 63 \
+ : -1)
+
+static const signed char b64[0x100] = {
+ B64 (0), B64 (1), B64 (2), B64 (3),
+ B64 (4), B64 (5), B64 (6), B64 (7),
+ B64 (8), B64 (9), B64 (10), B64 (11),
+ B64 (12), B64 (13), B64 (14), B64 (15),
+ B64 (16), B64 (17), B64 (18), B64 (19),
+ B64 (20), B64 (21), B64 (22), B64 (23),
+ B64 (24), B64 (25), B64 (26), B64 (27),
+ B64 (28), B64 (29), B64 (30), B64 (31),
+ B64 (32), B64 (33), B64 (34), B64 (35),
+ B64 (36), B64 (37), B64 (38), B64 (39),
+ B64 (40), B64 (41), B64 (42), B64 (43),
+ B64 (44), B64 (45), B64 (46), B64 (47),
+ B64 (48), B64 (49), B64 (50), B64 (51),
+ B64 (52), B64 (53), B64 (54), B64 (55),
+ B64 (56), B64 (57), B64 (58), B64 (59),
+ B64 (60), B64 (61), B64 (62), B64 (63),
+ B64 (64), B64 (65), B64 (66), B64 (67),
+ B64 (68), B64 (69), B64 (70), B64 (71),
+ B64 (72), B64 (73), B64 (74), B64 (75),
+ B64 (76), B64 (77), B64 (78), B64 (79),
+ B64 (80), B64 (81), B64 (82), B64 (83),
+ B64 (84), B64 (85), B64 (86), B64 (87),
+ B64 (88), B64 (89), B64 (90), B64 (91),
+ B64 (92), B64 (93), B64 (94), B64 (95),
+ B64 (96), B64 (97), B64 (98), B64 (99),
+ B64 (100), B64 (101), B64 (102), B64 (103),
+ B64 (104), B64 (105), B64 (106), B64 (107),
+ B64 (108), B64 (109), B64 (110), B64 (111),
+ B64 (112), B64 (113), B64 (114), B64 (115),
+ B64 (116), B64 (117), B64 (118), B64 (119),
+ B64 (120), B64 (121), B64 (122), B64 (123),
+ B64 (124), B64 (125), B64 (126), B64 (127),
+ B64 (128), B64 (129), B64 (130), B64 (131),
+ B64 (132), B64 (133), B64 (134), B64 (135),
+ B64 (136), B64 (137), B64 (138), B64 (139),
+ B64 (140), B64 (141), B64 (142), B64 (143),
+ B64 (144), B64 (145), B64 (146), B64 (147),
+ B64 (148), B64 (149), B64 (150), B64 (151),
+ B64 (152), B64 (153), B64 (154), B64 (155),
+ B64 (156), B64 (157), B64 (158), B64 (159),
+ B64 (160), B64 (161), B64 (162), B64 (163),
+ B64 (164), B64 (165), B64 (166), B64 (167),
+ B64 (168), B64 (169), B64 (170), B64 (171),
+ B64 (172), B64 (173), B64 (174), B64 (175),
+ B64 (176), B64 (177), B64 (178), B64 (179),
+ B64 (180), B64 (181), B64 (182), B64 (183),
+ B64 (184), B64 (185), B64 (186), B64 (187),
+ B64 (188), B64 (189), B64 (190), B64 (191),
+ B64 (192), B64 (193), B64 (194), B64 (195),
+ B64 (196), B64 (197), B64 (198), B64 (199),
+ B64 (200), B64 (201), B64 (202), B64 (203),
+ B64 (204), B64 (205), B64 (206), B64 (207),
+ B64 (208), B64 (209), B64 (210), B64 (211),
+ B64 (212), B64 (213), B64 (214), B64 (215),
+ B64 (216), B64 (217), B64 (218), B64 (219),
+ B64 (220), B64 (221), B64 (222), B64 (223),
+ B64 (224), B64 (225), B64 (226), B64 (227),
+ B64 (228), B64 (229), B64 (230), B64 (231),
+ B64 (232), B64 (233), B64 (234), B64 (235),
+ B64 (236), B64 (237), B64 (238), B64 (239),
+ B64 (240), B64 (241), B64 (242), B64 (243),
+ B64 (244), B64 (245), B64 (246), B64 (247),
+ B64 (248), B64 (249), B64 (250), B64 (251),
+ B64 (252), B64 (253), B64 (254), B64 (255)
+};
+
+#if UCHAR_MAX == 255
+# define uchar_in_range(c) true
+#else
+# define uchar_in_range(c) ((c) <= 255)
+#endif
+
+/* Return true if CH is a character from the Base64 alphabet, and
+ false otherwise. Note that '=' is padding and not considered to be
+ part of the alphabet. */
+bool
+isbase64 (char ch)
+{
+ return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)];
+}
+
+/* Decode base64 encoded input array IN of length INLEN to output
+ array OUT that can hold *OUTLEN bytes. Return true if decoding was
+ successful, i.e. if the input was valid base64 data, false
+ otherwise. If *OUTLEN is too small, as many bytes as possible will
+ be written to OUT. On return, *OUTLEN holds the length of decoded
+ bytes in OUT. Note that as soon as any non-alphabet characters are
+ encountered, decoding is stopped and false is returned. This means
+ that, when applicable, you must remove any line terminators that is
+ part of the data stream before calling this function. */
+bool
+base64_decode (const char * /* restrict */ in, size_t inlen,
+ char * /* restrict */ out, size_t *outlen)
+{
+ size_t outleft = *outlen;
+
+ while (inlen >= 2)
+ {
+ if (!isbase64 (in[0]) || !isbase64 (in[1]))
+ break;
+
+ if (outleft)
+ {
+ *out++ = ((b64[to_uchar (in[0])] << 2)
+ | (b64[to_uchar (in[1])] >> 4));
+ outleft--;
+ }
+
+ if (inlen == 2)
+ break;
+
+ if (in[2] == '=')
+ {
+ if (inlen != 4)
+ break;
+
+ if (in[3] != '=')
+ break;
+
+ }
+ else
+ {
+ if (!isbase64 (in[2]))
+ break;
+
+ if (outleft)
+ {
+ *out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0)
+ | (b64[to_uchar (in[2])] >> 2));
+ outleft--;
+ }
+
+ if (inlen == 3)
+ break;
+
+ if (in[3] == '=')
+ {
+ if (inlen != 4)
+ break;
+ }
+ else
+ {
+ if (!isbase64 (in[3]))
+ break;
+
+ if (outleft)
+ {
+ *out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0)
+ | b64[to_uchar (in[3])]);
+ outleft--;
+ }
+ }
+ }
+
+ in += 4;
+ inlen -= 4;
+ }
+
+ *outlen -= outleft;
+
+ if (inlen != 0)
+ return false;
+
+ return true;
+}
+
+/* Allocate an output buffer in *OUT, and decode the base64 encoded
+ data stored in IN of size INLEN to the *OUT buffer. On return, the
+ size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL,
+ if the caller is not interested in the decoded length. *OUT may be
+ NULL to indicate an out of memory error, in which case *OUTLEN
+ contains the size of the memory block needed. The function returns
+ true on successful decoding and memory allocation errors. (Use the
+ *OUT and *OUTLEN parameters to differentiate between successful
+ decoding and memory error.) The function returns false if the
+ input was invalid, in which case *OUT is NULL and *OUTLEN is
+ undefined. */
+bool
+base64_decode_alloc (const char *in, size_t inlen, char **out,
+ size_t *outlen)
+{
+ /* This may allocate a few bytes too much, depending on input,
+ but it's not worth the extra CPU time to compute the exact amount.
+ The exact amount is 3 * inlen / 4, minus 1 if the input ends
+ with "=" and minus another 1 if the input ends with "==".
+ Dividing before multiplying avoids the possibility of overflow. */
+ size_t needlen = 3 * (inlen / 4) + 2;
+
+ *out = malloc (needlen);
+ if (!*out)
+ return true;
+
+ if (!base64_decode (in, inlen, *out, &needlen))
+ {
+ free (*out);
+ *out = NULL;
+ return false;
+ }
+
+ if (outlen)
+ *outlen = needlen;
+
+ return true;
+}
View
45 sdt/base64.h
@@ -0,0 +1,45 @@
+/* base64.h -- Encode binary data using printable characters.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
+ Written by Simon Josefsson.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef BASE64_H
+# define BASE64_H
+
+/* Get size_t. */
+# include <stddef.h>
+
+/* Get bool. */
+# include <stdbool.h>
+
+/* This uses that the expression (n+(k-1))/k means the smallest
+ integer >= n/k, i.e., the ceiling of n/k. */
+# define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4)
+
+extern bool isbase64 (char ch);
+
+extern void base64_encode (const char * /* restrict */ in, size_t inlen,
+ char * /* restrict */ out, size_t outlen);
+
+extern size_t base64_encode_alloc (const char *in, size_t inlen, char **out);
+
+extern bool base64_decode (const char * /* restrict */ in, size_t inlen,
+ char * /* restrict */ out, size_t *outlen);
+
+extern bool base64_decode_alloc (const char *in, size_t inlen,
+ char **out, size_t *outlen);
+
+#endif /* BASE64_H */
View
40 sdt/configure
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+OS=`uname -s`
+
+case $OS in
+ 'Linux')
+ STATIC_LIB=/usr/lib/libresolv.a
+ LIB=-lcrypto
+ DEF="-DHAVE_ERR -DHAVE_SSL"
+ ;;
+ 'Darwin'|'NetBSD')
+ DEF="-DHAVE_ARC4RANDOM -DHAVE_ERR"
+ LIB="-lresolv"
+ ;;
+ 'SunOS')
+ LIB="-lresolv"
+ ;;
+ *)
+ echo "Guessing, adjust Makefile by hand ..."
+ LIB="-lresolv"
+ ;;
+
+esac
+
+cat<<EOF>Makefile
+CC=gcc
+RM=rm
+APP=sdt
+
+STATIC_LIB=${STATIC_LIB}
+DEF=${DEF}
+LIB=${LIB}
+
+all:
+ \$(CC) \$(DEF) -g -Wall \$(LIB) -o \$(APP) \$(APP).c \$(APP)_dns.c \$(APP)_err.c \$(APP)_rand.c base32.c base64.c \$(STATIC_LIB)
+
+clean:
+ -@\$(RM) *.o \$(APP)
+EOF
+
View
49 sdt/scripts/sd
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+USER=<YOUR USER NAME>
+DOMAIN=<YOUR DOMAIN NAME>
+PROXY="-L 8119:<YOUR PROXY>:8118"
+
+throbber() {
+ COUNT=0
+ echo "Tunnel disconnected, sleeping for $1 second(s): "
+ while [ "$COUNT" -lt "$1" ]; do
+ echo -n "$((COUNT+1)) "
+ sleep 1
+ COUNT=$((COUNT+1))
+ done
+ echo
+ echo "Trying to bring up tunnel now"
+}
+
+ssh-add -l
+if [ "$?" -ne "0" ]; then
+ ssh-add
+fi
+
+ARGS="$@"
+IP=2
+
+OPT_S=0
+for opt; do
+ if [ "$OPT_S" -eq "1" ]; then
+ IP=$(($IP+$opt))
+ OPT_S=0
+ fi
+ case $opt in
+ -s) OPT_S=1 ;;
+ esac
+done
+
+RETRY=1
+while [ "$RETRY" -lt "4" ]; do
+ ssh -t ${PROXY} -C -o ProxyCommand="~/bin/sdt ${ARGS} sshdns.${DOMAIN}" ${USER}@127.0.0.${IP} "screen -dR sshdns"
+ if [ "$?" -ne "0" ]; then
+ throbber $RETRY
+ else
+ exit 0
+ fi
+ RETRY=$((RETRY+1))
+done
+
+
View
24 sdt/scripts/sdftp
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+ARG="$@"
+IP=2
+
+USERNAME=<YOUR USER NAME>
+DOMAIN=<YOUR DOMAIN>
+
+SDT_BIN=~/bin/sdt
+
+OPT_S=0
+for opt; do
+ if [ "$OPT_S" -eq "1" ]; then
+ IP=$(($IP+$opt))
+ OPT_S=0
+ fi
+ case $opt in
+ -s) OPT_S=1 ;;
+ esac
+done
+
+sftp -C -o ProxyCommand="${SDT_BIN} ${ARG} sshdns.${DOMAIN}" ${USERNAME}@127.0.0.${IP}
+
+
View
510 sdt/sdt.c
@@ -0,0 +1,510 @@
+/*
+ * Socket over DNS client.
+ *
+ * Copyright (c) 2009 Michael Santos <michael.santos@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <signal.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "sdt.h"
+
+extern char *__progname;
+
+int woken = 0;
+int forcesend = 0;
+int nsauto = 1;
+
+ int
+main(int argc, char *argv[])
+{
+ SDT_STATE *ss = NULL;
+ pid_t pid = 0;
+ int nd = 0;
+ int ch = 0;
+ int di = 0;
+
+ IS_NULL(ss = (SDT_STATE *)calloc(1, sizeof(SDT_STATE)));
+
+ sdt_rand_init();
+ (void)sdt_dns_init();
+
+ ss->sess.o.id = (u_int16_t)arc4random();
+ ss->backoff = 1;
+ ss->maxbackoff = MAXBACKOFF;
+ ss->sleep = SLEEP_TXT;
+ ss->bufsz = 110;
+ ss->delay = 1000000/2; /* 2/second */
+ ss->faststart = 3;
+ ss->maxpollfail = MAXPOLLFAIL;
+ ss->type = ns_t_txt;
+ ss->verbose_lines = 100;
+ ss->protocol = PROTO_STATIC_FWD;
+ ss->target_port = 22;
+
+ ss->dname_next = &sdt_dns_dn_roundrobin;
+
+ ss->fd_in = fileno(stdin);
+ ss->fd_out = fileno(stdout);
+
+ while ( (ch = getopt(argc, argv, "A:B:b:D:dF:hM:m:n:p:R:r:S:s:T:t:V:vx:")) != -1) {
+ switch (ch) {
+ case 'A': /* alarm, delay buf */
+ ss->delay = (u_int32_t)atoi(optarg);
+ break;
+ case 'B': /* send buf size */
+ ss->bufsz = (size_t)atoi(optarg);
+ break;
+ case 'b': /* max backoff */
+ ss->maxbackoff = (u_int16_t)atoi(optarg);
+ break;
+ case 'D': { /* Dynamic forward */
+ char *hostname = NULL;
+
+ IS_NULL(hostname = strdup(optarg));
+ sdt_parse_forward(ss, hostname);
+ free(hostname);
+ }
+ break;
+ case 'd': /* Debug DNS */
+ sdt_dns_setopt(SDT_RES_DEBUG, 1);
+ break;
+ case 'F': /* fast start */
+ ss->faststart = (int32_t)atoi(optarg);
+ break;
+ case 'M':
+ ss->maxpollfail = (int32_t)atoi(optarg);
+ break;
+ case 'm':
+ ss->sleep = (u_int32_t)atoi(optarg);
+ break;
+ case 'n': /* strategy for shuffling domain name list */
+ if (strcasecmp(optarg, "roundrobin") == 0)
+ ss->dname_next = &sdt_dns_dn_roundrobin;
+ else if (strcasecmp(optarg, "random") == 0)
+ ss->dname_next = &sdt_dns_dn_random;
+ else
+ usage(ss);
+ break;
+ case 'p': /* Proxy mode */
+ ss->proxy_port = (in_port_t)atoi(optarg);
+ break;
+ case 'R': /* Retry lookup */
+ sdt_dns_setopt(SDT_RES_RETRY, (u_int32_t)atoi(optarg));
+ break;
+ case 'r':
+ if (sdt_dns_parsens(ss, optarg) < 0)
+ errx(EXIT_FAILURE, "Invalid NS address");
+
+ nsauto = 1;
+ break;
+ case 'S': /* Resolver strategies */
+ if (strcasecmp(optarg, "blast") == 0)
+ sdt_dns_setopt(SDT_RES_BLAST, 0);
+ else if (strcasecmp(optarg, "rotate") == 0)
+ sdt_dns_setopt(SDT_RES_ROTATE, 0);
+ else
+ usage(ss);
+ break;
+ case 's': /* forwarded session */
+ ss->sess.o.fwd = (u_int8_t)atoi(optarg);
+ break;
+ case 'T':
+ sdt_dns_setopt(SDT_RES_USEVC, (int32_t)atoi(optarg));
+ break;
+ case 't': /* DNS message type */
+ if (strcasecmp(optarg, "TXT") == 0)
+ ss->type = ns_t_txt;
+ else if (strcasecmp(optarg, "CNAME") == 0)
+ ss->type = ns_t_cname;
+ else if (strcasecmp(optarg, "NULL") == 0)
+ ss->type = ns_t_null;
+ else
+ usage(ss);
+ break;
+ case 'V':
+ ss->verbose_lines = atoi(optarg);
+ break;
+ case 'v':
+ ss->verbose++;
+ break;
+ case 'x': /* Transmit lookup timeout */
+ sdt_dns_setopt(SDT_RES_RETRANS, (int32_t)atoi(optarg));
+ break;
+
+ case 'h':
+ default:
+ usage(ss);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if ( (argc == 0) || (argc >= MAXDNAMELIST))
+ usage(ss);
+
+ ss->dname_max = argc;
+ IS_NULL(ss->dname = (char **)calloc(argc, sizeof(char *)));
+ for ( di = 0; di < argc; di++) {
+ if (strlen(argv[di]) > NS_MAXCDNAME - 1)
+ usage(ss);
+ IS_NULL(ss->dname[di] = strdup(argv[di]));
+ }
+
+ if (ss->proxy_port > 0)
+ IS_ERR(ss->fd_out = ss->fd_in = sdt_proxy_open(ss));
+
+ IS_ERR(nd = open("/dev/null", O_RDWR, 0));
+
+ VERBOSE(1, "session id = %u, opt = %u, session = %d\n", ss->sess.o.id,
+ ss->sess.o.opt, ss->sess.o.fwd);
+
+ switch (pid = fork()) {
+ case -1:
+ err(EXIT_FAILURE, "fork");
+ case 0:
+ if (ss->proxy_port > 0)
+ IS_ERR(dup2(fileno(stdout), nd));
+ IS_ERR(dup2(fileno(stdin), nd));
+ (void)signal(SIGUSR1,wakeup);
+ sdt_loop_poll(ss);
+ break;
+ default:
+ if (ss->proxy_port > 0)
+ IS_ERR(dup2(fileno(stdin), nd));
+ IS_ERR(dup2(fileno(stdout), nd));
+ (void)signal(SIGHUP,wakeup);
+ (void)signal(SIGTERM,wakeup);
+ (void)signal(SIGALRM,wakeup);
+ (void)signal(SIGCHLD,wakeup);
+ ss->child = pid;
+ sdt_loop_A(ss);
+
+ if (woken == 1) {
+ (void)kill(pid, SIGHUP);
+ (void)wait(NULL);
+ }
+
+ break;
+ }
+
+ free(ss->dname);
+ free(ss);
+ IS_ERR(close(nd));
+
+ exit(EXIT_SUCCESS);
+}
+
+
+ void
+sdt_parse_forward(SDT_STATE *ss, char *host)
+{
+ struct hostent *he = NULL;
+ struct in_addr in = {0};
+ char *port = NULL;
+
+ if ( (port = strchr(host, ':')) != NULL) {
+ *port++ = '\0';
+ ss->target_port = atoi(port);
+ }
+
+ if ( (he = gethostbyname(host)) == NULL)
+ errx(EXIT_FAILURE, "gethostbyname: %s", hstrerror(h_errno));
+
+ (void)memcpy(&in, he->h_addr, sizeof(in));
+ IS_NULL(ss->target = strdup(inet_ntoa(in)));
+ ss->protocol = PROTO_DYN_FWD;
+}
+
+
+ int
+sdt_proxy_open(SDT_STATE *ss)
+{
+ int s = -1;
+ int cs = -1;
+ struct sockaddr_in sa = {0};
+ struct sockaddr_in ca = {0};
+ socklen_t slen = 0;
+
+ int o = 1;
+
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(ss->proxy_port);
+ sa.sin_addr.s_addr = INADDR_ANY;
+
+ VERBOSE(1, "listening on port = %u\n", ss->proxy_port);
+
+ IS_ERR(s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
+
+ IS_ERR(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &o, sizeof(o)));
+
+ IS_ERR(bind(s, (struct sockaddr *)&sa, sizeof(sa)));
+
+ IS_ERR(listen(s, 0 /* XXX one connection only */));
+
+ slen = sizeof(ca);
+ IS_ERR(cs = accept(s, (struct sockaddr *)&ca, &slen));
+
+ (void)close(s);
+
+ return (cs);
+}
+
+
+/* Poll DNS server for data. Back off if no data is pending */
+ void
+sdt_loop_poll(SDT_STATE *ss)
+{
+ u_int32_t n = 0;
+
+ for ( ; ; n++) {
+ if (woken == 1) {
+ ss->backoff = 1;
+ woken = 0;
+ }
+
+ if (n%ss->backoff == 0)
+ sdt_send_poll(ss);
+
+ if (ss->maxpollfail > 0 && ss->pollfail > ss->maxpollfail) {
+ VERBOSE(1, "*** Exiting from polling (child)\n");
+ return;
+ }
+
+ usleep(ss->sleep);
+ }
+}
+
+ void
+sdt_send_poll(SDT_STATE *ss)
+{
+ char *buf = NULL;
+ size_t len = 0;
+ size_t n = 0;
+ size_t t = 0;
+
+
+ buf = sdt_dns_poll(ss, &len);
+
+ if ( (len <= 0) || (buf == NULL)) {
+ ss->backoff *= 3;
+ if (ss->backoff > ss->maxbackoff)
+ ss->backoff = ss->maxbackoff;
+
+ return;
+ }
+
+ /* Ramp up polling */
+ VERBOSE(1, "Ramping polling (record type = %d) ...\n",
+ ss->type);
+ ss->pollfail = 0;
+ ss->backoff = 1;
+
+ /* we received data, write to stdout, booyah! */
+ while ( (n = write(ss->fd_out, buf + t, len - t)) != (len - t)) {
+ if (n == -1)
+ err(EXIT_FAILURE, "sdt_send_poll: write");
+ t += n;
+ }
+ ss->sum += len;
+ free(buf);
+}
+
+
+/* Read from STDIN and base32 encode the data as A records */
+ void
+sdt_loop_A(SDT_STATE *ss)
+{
+ ssize_t n = 0;
+ char *buf = NULL;
+
+ int flags = 0;
+
+ flags = fcntl(ss->fd_in, F_GETFL, 0);
+ flags |= O_NONBLOCK;
+ (void)fcntl(ss->fd_in, F_SETFL, flags);
+
+ IS_NULL(buf = (char *)calloc(ss->bufsz, 1));
+
+ while ( (n = sdt_read(ss, buf, ss->bufsz)) > 0) {
+ VERBOSE(3, "Sending A record: %d of %u bytes\n", (int32_t)n, (u_int32_t)ss->bufsz);
+ sdt_send_A(ss, buf, n);
+ ss->sum_up += n;
+ if (woken != 0)
+ break;
+ VERBOSE(3, "A record: res timeout = %d, sleep = %f seconds\n",
+ ss->backoff, (float)(ss->sleep * ss->backoff)/1000000);
+ usleep(ss->sleep);
+ }
+
+ free(buf);
+ VERBOSE (1, "*** Exiting from A record read loop\n");
+}
+
+ ssize_t
+sdt_read(SDT_STATE *ss, char *buf, size_t nbytes)
+{
+ size_t n = 0;
+ size_t t = 0;
+
+ int rv = 0;
+ int breakloop = 0;
+
+ int fd = ss->fd_in;
+
+ sdt_alarm(ss);
+ do {
+ fd_set rfds;
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+
+ rv = select(fd+1, &rfds, NULL, NULL, NULL);
+
+ switch (rv) {
+ case 0:
+ break;
+ case -1:
+ switch (errno) {
+ case EBADF:
+ case EINVAL:
+ woken = 1;
+ breakloop = 1;
+ break;
+ case EINTR:
+ default:
+ break;
+ }
+ break;
+ default:
+ n = read(fd, buf + t, nbytes - t);
+ if (n == 0) {
+ woken = 1;
+ breakloop = 1;
+ }
+ if ( (ss->faststart > 0 || ss->delay == 0) && errno != EAGAIN)
+ breakloop = 1;
+ t += n;
+ break;
+ }
+
+ VERBOSE(3, "Looping in read: %u/%u bytes\n", (u_int32_t)n, (u_int32_t)t);
+ if ( (forcesend == 1) || (t == nbytes)) {
+ if (t > 0) {
+ breakloop = 1;
+ VERBOSE(3, " Forcing send Looping in read: %u/%u/%u bytes\n", (u_int32_t)n, (u_int32_t)t, (u_int32_t)nbytes);
+ }
+ if (forcesend == 1) {
+ forcesend = 0;
+ if (t == 0) sdt_alarm(ss);
+ }
+ }
+
+ if (woken != 0)
+ breakloop = 1;
+
+ } while (breakloop == 0);
+
+ ualarm(0, 0);
+ forcesend = 0;
+
+#define KEYSTROKELEN 32 /* size of one keystroke */
+ if (ss->faststart > 0 && t <= KEYSTROKELEN)
+ ss->faststart--;
+
+ return (t);
+}
+
+ void
+sdt_send_A(SDT_STATE *ss, char *buf, ssize_t n)
+{
+ while (sdt_dns_A(ss, buf, n) < 0) {
+ /* Re-send the buffer */
+ ss->backoff++;
+ VERBOSE(1, "re-sending data (A record): res timeout = %d seconds\n", ss->backoff);
+ if (ss->backoff > ss->maxbackoff)
+ ss->backoff = ss->maxbackoff;
+ sdt_dns_setopt(SDT_RES_RETRANS, ss->backoff);
+ }
+ /* Inform the child to increase polling of server */
+ (void)kill(ss->child, SIGUSR1);
+}
+
+
+ void
+sdt_alarm(SDT_STATE *ss)
+{
+ if (ss->faststart <= 0)
+ ualarm(ss->delay, 0);
+}
+
+ void
+wakeup(int sig)
+{
+ switch (sig) {
+ case SIGUSR1:
+ case SIGTERM:
+ case SIGHUP:
+ woken = 1;
+ break;
+ case SIGCHLD:
+ woken = 2;
+ break;
+ case SIGALRM:
+ forcesend = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+ void
+usage(SDT_STATE *ss)
+{
+ (void)fprintf(stderr, "%s: [-h|-r|-v] <domain name>\n", __progname);
+ (void)fprintf(stderr, "[version %s]\n", SDT_VERSION);
+ (void)fprintf(stderr, "-h\tUsage\n");
+ (void)fprintf(stderr, "-A\tDelay A queries to force full buffer reads [default: %d microseconds]\n", ss->delay);
+ (void)fprintf(stderr, "-B\tSize of read buffer (A queries) [default: %d bytes]\n", (u_int32_t)ss->bufsz);
+ (void)fprintf(stderr, "-b\tMaximum backoff for polling server [default: %d]\n", ss->maxbackoff);
+ (void)fprintf(stderr, "-D\tDynamically forward a session\n");
+ (void)fprintf(stderr, "-F <num>\tFast start, number of small packets to pass w/out buffering (0 to disable) [default: %d]\n", ss->faststart);
+ (void)fprintf(stderr, "-M\tMaximum number of polling query failures [default: %d]\n", ss->maxpollfail);
+ (void)fprintf(stderr, "-m\tMinimum time to sleep between nameserver queries [default: %d us]\n", ss->sleep);
+ (void)fprintf(stderr, "-n <roundrobin|random>\tStrategy for shuffling domain names [default: roundrobin]\n");
+ (void)fprintf(stderr, "-p <port>\tproxy port, listen on a TCP port instead of using stdin/stdout\n");
+ (void)fprintf(stderr, "-R <number>\tNumber of retries for lookup\n");
+ (void)fprintf(stderr, "-r\tNameserver (or keyword: random, opendns, verizon, speakeasy, google)\n");
+ (void)fprintf(stderr, "-S [rotate|blast]\tResolver strategy\n");
+ (void)fprintf(stderr, "-s <number>\tForward session\n");
+ (void)fprintf(stderr, "-T <number>\tUse TCP [0 = new connection for each request, 1 = pipeline requests]\n");
+ (void)fprintf(stderr, "-t <DNS type>\tTXT, CNAME, NULL [Default = TXT]\n");
+ (void)fprintf(stderr, "-V <num>\tNumber of debug messages\n");
+ (void)fprintf(stderr, "-v\tPrint debug messages\n");
+ (void)fprintf(stderr, "-x <number>\tResolver transmit timeout\n");
+ (void)fprintf(stderr, "\nExample: %s -r 127.0.0.1 sshdns.a.example.com\n\n", __progname);
+
+ if (ss->verbose > 0)
+ sdt_dns_print_servers(ss);
+
+ exit(EXIT_FAILURE);
+}
View
207 sdt/sdt.h
@@ -0,0 +1,207 @@
+/*
+ * Socket over DNS client.
+ *
+ * Copyright (c) 2009 Michael Santos <michael.santos@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+
+#include <arpa/nameser.h>
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <netdb.h>
+extern int h_errno;
+
+
+#define SDT_VERSION "0.9"
+
+#ifdef HAVE_ERRX
+#include <err.h>
+#else
+#define err sdt_err
+#define errx sdt_errx
+#define warn sdt_warn
+#define warnx sdt_warnx
+#endif /* HAVE_ERRX */
+
+#ifndef HAVE_ARC4RANDOM
+#ifdef HAVE_SSL
+#define arc4random sdt_rand
+#else
+#define arc4random random
+#endif /* HAVE_SSL */
+#endif /* HAVE_ARC4RANDOM */
+
+
+#define IS_ERR(x) do { \
+ if ((x) == -1) { \
+ err(EXIT_FAILURE, "%s", #x); \
+ } \
+} while (0)
+
+#define IS_NULL(x) do { \
+ if ((x) == NULL) { \
+ err(EXIT_FAILURE, "%s", #x); \
+ } \
+} while (0)
+
+#define TIMESTAMP() do { \
+ char outstr[200]; \
+ time_t t; \
+ struct tm *tmp; \
+ \
+ t = time(NULL); \
+ tmp = localtime(&t); \
+ if (tmp == NULL) { \
+ perror("localtime"); \
+ exit(EXIT_FAILURE); \
+ } \
+ \
+ if (strftime(outstr, sizeof(outstr), "%Y-%m-%d %H:%M:%S ", tmp) == 0) { \
+ (void)fprintf(stderr, "strftime returned 0"); \
+ exit(EXIT_FAILURE); \
+ } \
+ \
+ (void)fprintf(stderr, "%s", outstr); \
+} while (0)
+
+
+#define VERBOSE(x, ...) do { \
+ if (ss->verbose_lines == 0) { \
+ break; \
+ } \
+ ss->verbose_lines--; \
+ if (ss->verbose >= 4) { \
+ TIMESTAMP(); \
+ } \
+ if (ss->verbose >= x) { \
+ (void)fprintf (stderr, __VA_ARGS__); \
+ } \
+} while (0)
+
+#define MAXBUF 47 /* MIME has a maximum line length of 76 bytes:
+ 76 * 5 / 8 = 47 bytes */
+
+#define SLEEP_TXT 20000 /* microseconds */
+#define MAXBACKOFF 3000 /* 3000 * 20000 = 60,000,000 (1/minute) */
+#define MAXPOLLFAIL 10 /* Number of TXT record failures before giving up */
+
+#define MAXDNAMELIST 256 /* arbitrary cutoff for number of domains */
+
+
+typedef union _SDT_ID {
+ struct {
+ u_int32_t opt:8,
+ fwd:8,
+ id:16;
+ } o;
+ u_int32_t id;
+} SDT_ID;
+
+typedef struct _SDT_STATE {
+ char **dname;
+ int dname_max;
+ int dname_iterator;
+ SDT_ID sess;
+ size_t sum;
+ size_t sum_up;
+ size_t bufsz;
+ u_int16_t backoff;
+ u_int16_t maxbackoff;
+ u_int32_t sleep;
+ u_int32_t type;
+ int32_t delay;
+ int32_t faststart;
+ int32_t pollfail;
+ int32_t maxpollfail;
+ pid_t child;
+ int verbose;
+ int verbose_lines;
+
+ in_port_t proxy_port;
+ int fd_in;
+ int fd_out;
+
+ int protocol;
+ char *target;
+ in_port_t target_port;
+
+ char *(*dname_next)(void *state);
+} SDT_STATE;
+
+/* Protocol version */
+enum {
+ PROTO_OZYMANDNS,
+ PROTO_STATIC_FWD,
+ PROTO_DYN_FWD
+};
+
+/* Resolver options */
+enum {
+ SDT_RES_RETRANS, /* Resolver timeout */
+ SDT_RES_RETRY, /* Number of times to retry lookup */
+ SDT_RES_USEVC, /* Use TCP for lookup */
+ SDT_RES_ROTATE, /* Rotate through available nameservers */
+ SDT_RES_BLAST, /* Query all nameservers */
+ SDT_RES_DEBUG, /* Enable resolver debugging */
+};
+
+void sdt_parse_forward(SDT_STATE *ss, char *host);
+int sdt_proxy_open(SDT_STATE *ss);
+void sdt_loop_poll(SDT_STATE *ss);
+void sdt_loop_A(SDT_STATE *ss);
+void sdt_send_poll(SDT_STATE *ss);
+void sdt_send_A(SDT_STATE *ss, char *buf, ssize_t n);
+ssize_t sdt_read(SDT_STATE *ss, char *buf, size_t nbytes);
+void sdt_alarm(SDT_STATE *ss);
+
+int sdt_dns_init(void);
+void sdt_dns_setopt(int opt, int val);
+int sdt_dns_setns(char *ns);
+int sdt_dns_parsens(SDT_STATE *ss, char *buf);
+int sdt_dns_A(SDT_STATE *ss, char *buf, ssize_t n);
+char *sdt_dns_poll(SDT_STATE *ss, size_t *len);
+char *sdt_dns_parse(SDT_STATE *ss, char *pkt, int *pktlen);
+char *sdt_dns_dec_CNAME(SDT_STATE *ss, u_char *data, u_int16_t *n);
+char *sdt_dns_dec_TXT(SDT_STATE *ss, u_char *data, u_int16_t *n);
+char *sdt_dns_dec_NULL(SDT_STATE *ss, u_char *data, u_int16_t *n);
+void sdt_dns_print_servers(SDT_STATE *ss);
+char *sdt_dns_dn_roundrobin(void *state);
+char *sdt_dns_dn_random(void *state);
+
+
+void sdt_rand_init(void);
+#ifndef HAVE_ARC4RANDOM
+u_int32_t sdt_rand(void);
+#endif
+
+void wakeup(int sig);
+void usage(SDT_STATE *ss);
+
+#ifndef HAVE_ERRX
+void sdt_err(int rv, char *fmt, ...);
+void sdt_errx(int rv, char *fmt, ...);
+void sdt_warn(char *fmt, ...);
+void sdt_warnx(char *fmt, ...);
+#endif /* HAVE_ERRX */
+
View
451 sdt/sdt_dns.c
@@ -0,0 +1,451 @@
+/*
+ * Socket over DNS client.
+ *
+ * Copyright (c) 2009 Michael Santos <michael.santos@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h>
+
+#include <ctype.h>
+
+#include "base32.h"
+#include "base64.h"
+
+#include "sdt.h"
+#include "sdt_servers.h"
+
+int nx = 0;
+
+ int
+sdt_dns_init(void)
+{
+ /*
+ if ( (__res != NULL) && (__res.res_init != 0))
+ __res.res_init = 0;
+ */
+
+ IS_ERR(res_init());
+
+ _res.options &= ~(RES_DNSRCH|RES_DEFNAMES);
+ _res.retrans = 3;
+ _res.retry = 1;
+
+ return (0);
+}
+
+ void
+sdt_dns_setopt(int opt, int val)
+{
+ switch (opt) {
+ case SDT_RES_RETRANS:
+ _res.retrans = val;
+ break;
+ case SDT_RES_RETRY:
+ _res.retry = val;
+ break;
+ case SDT_RES_USEVC:
+ _res.options |= RES_USEVC;
+ if (val > 0)
+ _res.options |= RES_STAYOPEN;
+ break;
+ case SDT_RES_ROTATE:
+ _res.options |= RES_ROTATE;
+ break;
+ case SDT_RES_BLAST:
+ _res.options |= RES_BLAST;
+ break;
+ case SDT_RES_DEBUG:
+ _res.options |= RES_DEBUG;
+ break;
+ }
+}
+
+ int
+sdt_dns_setns(char *ns)
+{
+ struct hostent *he = NULL;
+
+ if ( (ns == NULL) || (nx > MAXNS - 1))
+ return (-1);
+
+ if ( (he = gethostbyname(ns)) == NULL) {
+ warnx("gethostbyname: %s", hstrerror(h_errno));
+ return (-1);
+ }
+
+ (void)memcpy(&_res.nsaddr_list[nx++].sin_addr, he->h_addr_list[0], he->h_length);
+ _res.nscount = nx;
+
+ return (0);
+}
+
+ int
+sdt_dns_A(SDT_STATE *ss, char *buf, ssize_t n)
+{
+ char *p = NULL;
+ char dn[NS_MAXDNAME];
+ char query[NS_MAXDNAME];
+ char pkt[NS_PACKETSZ];
+
+ int i = 0;
+ int j = 0;
+
+ u_int16_t nonce = 0;
+
+ if (n < 1)
+ return (-1);
+
+ (void)memset(dn, 0, sizeof(dn));
+ (void)memset(query, 0, sizeof(query));
+ (void)memset(pkt, 0, sizeof(pkt));
+
+ nonce = (u_int16_t)arc4random();
+
+ /* Base32 encode the buffer and lowercase the result */
+ if (base32_encode_length(n) >= sizeof(dn))
+ errx(EXIT_FAILURE, "buffer overflow, biatch!");
+
+ base32_encode_into(buf, n, dn);
+
+ for (p = dn; *p != '\0'; p++) {
+ *p = tolower(*p);
+ if (++i%NS_MAXLABEL == 0)
+ query[j++] = '.';
+ query[j++] = *p;
+ }
+ (void)memcpy(dn, query, sizeof(dn));
+
+ switch (ss->protocol) {
+ case PROTO_DYN_FWD:
+ (void)snprintf(query, sizeof(query), "%s.%u-%u.id-%u.u.%s-%u.x.%s",
+ dn, nonce, (u_int32_t)ss->sum_up, htonl(ss->sess.id), ss->target, ss->target_port, ss->dname_next(ss));
+ break;
+ default:
+ /* Create the domain name:
+ * $temp_payload.$nonce-$sum_up.id-$id.up.$extension
+ */
+ (void)snprintf(query, sizeof(query), "%s.%u-%u.id-%u.up.%s",
+ dn, nonce, (u_int32_t)ss->sum_up, htonl(ss->sess.id), ss->dname_next(ss));
+ break;
+ }
+
+ VERBOSE(2, "A:%s\n", query);
+ if (res_search(query, ns_c_in, ns_t_a, (u_char *)&pkt, sizeof(pkt)) < 0) {
+ VERBOSE(1, "sdt_dns_A: res_search: %s\n", hstrerror(h_errno));
+ return (-1);
+ }
+
+ return (0);
+}
+
+ char *
+sdt_dns_poll(SDT_STATE *ss, size_t *len)
+{
+ char query[NS_MAXDNAME];
+ char pkt[NS_PACKETSZ];
+
+ char *buf = NULL;
+ int buflen = 0;
+
+ u_int16_t nonce = 0;
+
+ (void)memset(pkt, 0, sizeof(pkt));
+
+ nonce = (u_int16_t)arc4random();
+
+ switch (ss->protocol) {
+ case PROTO_DYN_FWD:
+ (void)snprintf(query, sizeof(query), "%u-%u.id-%u.d.%s-%u.x.%s",
+ (u_int32_t)ss->sum, nonce, htonl(ss->sess.id), ss->target, ss->target_port, ss->dname_next(ss));
+ break;
+ default:
+ /* Create the TXT query:
+ * $sum-$nonce.id-$id.down.$extension
+ */
+ (void)snprintf(query, sizeof(query), "%u-%u.id-%u.down.%s",
+ (u_int32_t)ss->sum, nonce, htonl(ss->sess.id), ss->dname_next(ss));
+ break;
+ }
+
+ VERBOSE(2, "POLL:%s\n", query);
+
+ *len = 0;
+ if ( (buflen = res_search(query, ns_c_in, ss->type, (u_char *)&pkt, sizeof(pkt))) < 0) {
+ VERBOSE(1, "sdt_dns_poll: res_search: %s\n", hstrerror(h_errno));
+ ss->pollfail++;
+ return (NULL);
+ }
+
+ buf = sdt_dns_parse(ss, pkt, &buflen);
+ *len = buflen;
+
+ return (buf);
+}
+
+/* Retrieve the answer and base64
+ * decode it
+ */
+ char *
+sdt_dns_parse(SDT_STATE *ss, char *pkt, int *pktlen)
+{
+ ns_msg nsh;
+ ns_rr rr;
+ char *buf = NULL;
+ u_int16_t rrlen = 0;
+ int type = 0;
+
+ if (ns_initparse((u_char *)pkt, *pktlen, &nsh) < 0) {
+ VERBOSE(1, "Invalid response in record\n");
+ return (NULL);
+ }
+
+#if 0
+ for (i = 0; i < ns_msg_count(nsh, ns_s_an); i++) {
+ if (ns_parserr(&nsh, ns_s_an, i, &rr)) {
+#endif
+ if (ns_parserr(&nsh, ns_s_an, 0, &rr)) {
+ VERBOSE(1, "ns_parserr\n");
+ *pktlen = 0;
+ return (NULL);
+ }
+
+ if (ns_rr_type(rr) != ss->type) {
+ VERBOSE(1, "ns_rr_type != ns_t_txt\n");
+ /* continue; */
+ *pktlen = 0;
+ return (NULL);
+ }
+
+ type = ns_rr_type(rr);
+ rrlen = ns_rr_rdlen(rr);
+
+ if (rrlen > *pktlen)
+ return (NULL);
+
+ switch (type) {
+ case ns_t_txt:
+ buf = sdt_dns_dec_TXT(ss, (u_char *)ns_rr_rdata(rr), &rrlen);
+ break;
+ case ns_t_cname:
+ buf = sdt_dns_dec_CNAME(ss, (u_char *)ns_rr_rdata(rr), &rrlen);
+ break;
+ case ns_t_null:
+ buf = sdt_dns_dec_NULL(ss, (u_char *)ns_rr_rdata(rr), &rrlen);
+ break;
+ }
+#if 0
+ }
+#endif
+