2006-06-05 18:47:09 +00:00
|
|
|
/*
|
2015-06-28 18:01:48 +00:00
|
|
|
* Copyright (c) 2006-2015 Erik Ekman <yarrick@kryo.se>,
|
2015-08-21 08:57:54 +00:00
|
|
|
* 2006-2009 Bjorn Andersson <flex@kryo.se>,
|
|
|
|
* 2015 Frekk van Blagh <frekk@frekkworks.com>
|
2006-06-05 18:47:09 +00:00
|
|
|
*
|
2014-08-07 19:14:10 +00:00
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
2006-06-05 18:47:09 +00:00
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2014-05-29 16:37:40 +00:00
|
|
|
#include <strings.h>
|
2006-06-05 18:47:09 +00:00
|
|
|
#include <signal.h>
|
|
|
|
#include <unistd.h>
|
2008-07-12 12:26:41 +00:00
|
|
|
#include <sys/param.h>
|
2007-06-17 11:46:05 +00:00
|
|
|
#include <sys/time.h>
|
2009-01-24 22:19:11 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <zlib.h>
|
2015-08-21 08:57:54 +00:00
|
|
|
#include <err.h>
|
2009-01-24 22:19:11 +00:00
|
|
|
|
2009-09-20 09:09:18 +00:00
|
|
|
#include "common.h"
|
2015-08-21 08:57:54 +00:00
|
|
|
#include "version.h"
|
2009-09-20 09:09:18 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
#ifdef WINDOWS32
|
|
|
|
#include "windows.h"
|
|
|
|
#include <winsock2.h>
|
|
|
|
#else
|
|
|
|
#include <arpa/nameser.h>
|
|
|
|
#ifdef DARWIN
|
|
|
|
#define BIND_8_COMPAT
|
|
|
|
#include <arpa/nameser_compat.h>
|
|
|
|
#endif
|
|
|
|
#define _XPG4_2
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <grp.h>
|
|
|
|
#include <sys/uio.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <syslog.h>
|
|
|
|
#endif
|
2009-12-29 20:00:57 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
#include "dns.h"
|
|
|
|
#include "encoding.h"
|
|
|
|
#include "base32.h"
|
|
|
|
#include "base64.h"
|
|
|
|
#include "base64u.h"
|
|
|
|
#include "base128.h"
|
|
|
|
#include "user.h"
|
|
|
|
#include "login.h"
|
|
|
|
#include "tun.h"
|
|
|
|
#include "fw_query.h"
|
|
|
|
#include "version.h"
|
|
|
|
#include "server.h"
|
2009-12-29 20:00:57 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
#ifdef HAVE_SYSTEMD
|
|
|
|
# include <systemd/sd-daemon.h>
|
|
|
|
#endif
|
2009-12-29 20:00:57 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
#ifdef WINDOWS32
|
|
|
|
WORD req_version = MAKEWORD(2, 2);
|
|
|
|
WSADATA wsa_data;
|
|
|
|
#endif
|
2007-02-04 17:00:20 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
/* Ask ipify.org webservice to get external ip */
|
2007-02-04 17:00:20 +00:00
|
|
|
static int
|
2015-08-21 08:57:54 +00:00
|
|
|
get_external_ip(struct in_addr *ip)
|
2007-02-04 17:00:20 +00:00
|
|
|
{
|
2015-08-21 08:57:54 +00:00
|
|
|
int sock;
|
|
|
|
struct addrinfo *addr;
|
|
|
|
int res;
|
|
|
|
const char *getstr = "GET / HTTP/1.0\r\n"
|
|
|
|
/* HTTP 1.0 to avoid chunked transfer coding */
|
|
|
|
"Host: api.ipify.org\r\n\r\n";
|
|
|
|
char buf[512];
|
|
|
|
char *b;
|
|
|
|
int len;
|
2006-06-05 18:47:09 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
res = getaddrinfo("api.ipify.org", "80", NULL, &addr);
|
|
|
|
if (res < 0) return 1;
|
2006-06-05 18:47:09 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
|
|
|
if (sock < 0) {
|
|
|
|
freeaddrinfo(addr);
|
|
|
|
return 2;
|
2009-08-06 19:48:55 +00:00
|
|
|
}
|
2009-09-20 21:10:41 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
res = connect(sock, addr->ai_addr, addr->ai_addrlen);
|
|
|
|
freeaddrinfo(addr);
|
|
|
|
if (res < 0) return 3;
|
2009-08-06 19:48:55 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
res = write(sock, getstr, strlen(getstr));
|
|
|
|
if (res != strlen(getstr)) return 4;
|
2014-06-01 06:34:18 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
/* Zero buf before receiving, leave at least one zero at the end */
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
res = read(sock, buf, sizeof(buf) - 1);
|
|
|
|
if (res < 0) return 5;
|
|
|
|
len = res;
|
2009-06-14 13:31:35 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
res = close(sock);
|
|
|
|
if (res < 0) return 6;
|
2009-12-29 20:00:57 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
b = buf;
|
|
|
|
while (len > 9) {
|
|
|
|
/* Look for split between headers and data */
|
|
|
|
if (strncmp("\r\n\r\n", b, 4) == 0) break;
|
|
|
|
b++;
|
|
|
|
len--;
|
2009-12-29 20:00:57 +00:00
|
|
|
}
|
2015-08-21 08:57:54 +00:00
|
|
|
if (len < 10) return 7;
|
|
|
|
b += 4;
|
2009-06-14 13:31:35 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
res = inet_aton(b, ip);
|
|
|
|
return (res == 0);
|
2009-08-06 19:48:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-08-21 08:57:54 +00:00
|
|
|
sigint(int sig)
|
2009-08-06 19:48:55 +00:00
|
|
|
{
|
2015-08-21 08:57:54 +00:00
|
|
|
server_stop();
|
2009-06-14 13:31:35 +00:00
|
|
|
}
|
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
#ifdef WINDOWS32
|
|
|
|
#define LOG_EMERG 0
|
|
|
|
#define LOG_ALERT 1
|
|
|
|
#define LOG_CRIT 2
|
|
|
|
#define LOG_ERR 3
|
|
|
|
#define LOG_WARNING 4
|
|
|
|
#define LOG_NOTICE 5
|
|
|
|
#define LOG_INFO 6
|
|
|
|
#define LOG_DEBUG 7
|
2009-08-15 12:43:02 +00:00
|
|
|
static void
|
2015-08-21 08:57:54 +00:00
|
|
|
syslog(int a, const char *str, ...)
|
2009-06-14 13:31:35 +00:00
|
|
|
{
|
2015-08-21 08:57:54 +00:00
|
|
|
/* TODO: implement (add to event log), move to common.c */
|
|
|
|
;
|
2009-06-14 13:31:35 +00:00
|
|
|
}
|
2009-01-24 22:19:11 +00:00
|
|
|
#endif
|
2009-01-24 22:12:00 +00:00
|
|
|
|
2006-06-09 20:35:26 +00:00
|
|
|
static void
|
2015-06-28 18:01:48 +00:00
|
|
|
print_usage() {
|
2006-08-24 21:26:40 +00:00
|
|
|
extern char *__progname;
|
|
|
|
|
2015-06-30 19:32:21 +00:00
|
|
|
fprintf(stderr, "Usage: %s [-v] [-h] "
|
|
|
|
"[-4] [-6] [-c] [-s] [-f] [-D] [-u user] "
|
2009-06-24 17:28:13 +00:00
|
|
|
"[-t chrootdir] [-d device] [-m mtu] [-z context] "
|
2015-06-28 18:01:48 +00:00
|
|
|
"[-l ipv4 listen address] [-L ipv6 listen address] "
|
|
|
|
"[-p port] [-n external ip] [-b dnsport] "
|
|
|
|
"[-P password] [-F pidfile] [-i max idle time] "
|
2009-08-15 21:52:49 +00:00
|
|
|
"tunnel_ip[/netmask] topdomain\n", __progname);
|
2015-06-28 18:01:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
usage() {
|
|
|
|
print_usage();
|
2006-06-09 20:35:26 +00:00
|
|
|
exit(2);
|
|
|
|
}
|
|
|
|
|
2006-06-11 13:14:57 +00:00
|
|
|
static void
|
|
|
|
help() {
|
2009-02-28 14:35:03 +00:00
|
|
|
fprintf(stderr, "iodine IP over DNS tunneling server\n");
|
2015-06-28 18:01:48 +00:00
|
|
|
print_usage();
|
2009-02-28 14:35:03 +00:00
|
|
|
fprintf(stderr, " -v to print version info and exit\n");
|
|
|
|
fprintf(stderr, " -h to print this help and exit\n");
|
2015-06-30 19:32:21 +00:00
|
|
|
fprintf(stderr, " -4 to listen only on IPv4\n");
|
|
|
|
fprintf(stderr, " -6 to listen only on IPv6\n");
|
2009-02-28 14:35:03 +00:00
|
|
|
fprintf(stderr, " -c to disable check of client IP/port on each request\n");
|
|
|
|
fprintf(stderr, " -s to skip creating and configuring the tun device, "
|
2008-09-09 19:55:45 +00:00
|
|
|
"which then has to be created manually\n");
|
2009-02-28 14:35:03 +00:00
|
|
|
fprintf(stderr, " -f to keep running in foreground\n");
|
|
|
|
fprintf(stderr, " -D to increase debug level\n");
|
2009-12-29 20:00:57 +00:00
|
|
|
fprintf(stderr, " (using -DD in UTF-8 terminal: \"LC_ALL=C luit iodined -DD ...\")\n");
|
2009-02-28 14:35:03 +00:00
|
|
|
fprintf(stderr, " -u name to drop privileges and run as user 'name'\n");
|
|
|
|
fprintf(stderr, " -t dir to chroot to directory dir\n");
|
|
|
|
fprintf(stderr, " -d device to set tunnel device name\n");
|
|
|
|
fprintf(stderr, " -m mtu to set tunnel device mtu\n");
|
2009-06-24 17:28:13 +00:00
|
|
|
fprintf(stderr, " -z context to apply SELinux context after initialization\n");
|
2015-06-28 18:01:48 +00:00
|
|
|
fprintf(stderr, " -l IPv4 address to listen on for incoming dns traffic "
|
2008-09-09 19:55:45 +00:00
|
|
|
"(default 0.0.0.0)\n");
|
2015-06-28 18:01:48 +00:00
|
|
|
fprintf(stderr, " -L IPv6 address to listen on for incoming dns traffic "
|
|
|
|
"(default ::)\n");
|
2009-02-28 14:35:03 +00:00
|
|
|
fprintf(stderr, " -p port to listen on for incoming dns traffic (default 53)\n");
|
|
|
|
fprintf(stderr, " -n ip to respond with to NS queries\n");
|
|
|
|
fprintf(stderr, " -b port to forward normal DNS queries to (on localhost)\n");
|
|
|
|
fprintf(stderr, " -P password used for authentication (max 32 chars will be used)\n");
|
2009-08-15 21:52:49 +00:00
|
|
|
fprintf(stderr, " -F pidfile to write pid to a file\n");
|
2013-12-23 20:58:28 +00:00
|
|
|
fprintf(stderr, " -i maximum idle time before shutting down\n");
|
2009-02-28 14:35:03 +00:00
|
|
|
fprintf(stderr, "tunnel_ip is the IP number of the local tunnel interface.\n");
|
|
|
|
fprintf(stderr, " /netmask sets the size of the tunnel network.\n");
|
|
|
|
fprintf(stderr, "topdomain is the FQDN that is delegated to this server.\n");
|
2006-06-11 13:14:57 +00:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2006-06-11 13:27:48 +00:00
|
|
|
static void
|
|
|
|
version() {
|
2009-02-28 14:35:03 +00:00
|
|
|
fprintf(stderr, "iodine IP over DNS tunneling server\n");
|
2015-08-21 08:57:54 +00:00
|
|
|
fprintf(stderr, "Git version: %s\n; protocol version %08X", GITREVISION, PROTOCOL_VERSION);
|
2006-06-11 13:27:48 +00:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2015-06-28 20:41:54 +00:00
|
|
|
static void
|
|
|
|
prepare_dns_fd(int fd)
|
|
|
|
{
|
|
|
|
#ifndef WINDOWS32
|
|
|
|
int flag = 1;
|
|
|
|
|
|
|
|
/* To get destination address from each UDP datagram, see read_dns() */
|
|
|
|
setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, (const void*) &flag, sizeof(flag));
|
|
|
|
#ifdef IPV6_RECVPKTINFO
|
|
|
|
setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, (const void*) &flag, sizeof(flag));
|
|
|
|
#endif
|
|
|
|
#ifdef IPV6_PKTINFO
|
|
|
|
setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, (const void*) &flag, sizeof(flag));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2006-06-05 18:47:09 +00:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
2009-02-15 18:24:12 +00:00
|
|
|
extern char *__progname;
|
2015-06-28 10:54:35 +00:00
|
|
|
char *listen_ip4;
|
2015-06-28 18:01:48 +00:00
|
|
|
char *listen_ip6;
|
2014-05-31 08:06:44 +00:00
|
|
|
char *errormsg;
|
2009-01-24 22:19:11 +00:00
|
|
|
#ifndef WINDOWS32
|
2007-07-12 13:46:58 +00:00
|
|
|
struct passwd *pw;
|
2009-01-24 22:19:11 +00:00
|
|
|
#endif
|
2007-07-12 13:46:58 +00:00
|
|
|
int foreground;
|
2006-06-09 20:35:26 +00:00
|
|
|
char *username;
|
2007-07-12 13:46:58 +00:00
|
|
|
char *newroot;
|
2009-06-24 17:28:13 +00:00
|
|
|
char *context;
|
2006-06-24 10:28:24 +00:00
|
|
|
char *device;
|
2009-08-15 21:52:49 +00:00
|
|
|
char *pidfile;
|
2015-06-30 19:32:21 +00:00
|
|
|
int addrfamily;
|
2015-06-28 10:54:35 +00:00
|
|
|
struct dnsfd dns_fds;
|
2007-07-12 13:46:58 +00:00
|
|
|
int tun_fd;
|
2008-08-07 21:18:15 +00:00
|
|
|
|
2014-06-01 06:34:18 +00:00
|
|
|
/* settings for forwarding normal DNS to
|
2008-08-07 21:18:15 +00:00
|
|
|
* local real DNS server */
|
|
|
|
int bind_fd;
|
|
|
|
int bind_enable;
|
2014-06-01 06:34:18 +00:00
|
|
|
|
2007-07-12 13:46:58 +00:00
|
|
|
int choice;
|
2006-11-05 13:18:57 +00:00
|
|
|
int port;
|
2007-07-12 13:46:58 +00:00
|
|
|
int mtu;
|
2008-07-12 11:45:22 +00:00
|
|
|
int skipipconfig;
|
2009-01-04 12:39:28 +00:00
|
|
|
char *netsize;
|
2012-09-03 08:34:27 +00:00
|
|
|
int ns_get_externalip;
|
2009-06-24 16:40:51 +00:00
|
|
|
int retval;
|
2013-12-23 20:58:28 +00:00
|
|
|
int max_idle_time = 0;
|
2015-06-28 10:54:35 +00:00
|
|
|
struct sockaddr_storage dns4addr;
|
2015-06-28 18:25:22 +00:00
|
|
|
int dns4addr_len;
|
2015-06-28 18:01:48 +00:00
|
|
|
struct sockaddr_storage dns6addr;
|
2015-06-28 18:25:22 +00:00
|
|
|
int dns6addr_len;
|
2013-12-23 09:48:46 +00:00
|
|
|
#ifdef HAVE_SYSTEMD
|
|
|
|
int nb_fds;
|
|
|
|
#endif
|
2006-06-09 20:35:26 +00:00
|
|
|
|
2009-08-15 19:35:07 +00:00
|
|
|
#ifndef WINDOWS32
|
2009-08-15 19:28:48 +00:00
|
|
|
pw = NULL;
|
2009-08-15 19:35:07 +00:00
|
|
|
#endif
|
2014-05-31 08:06:44 +00:00
|
|
|
errormsg = NULL;
|
2006-06-09 20:35:26 +00:00
|
|
|
username = NULL;
|
2006-06-11 15:24:20 +00:00
|
|
|
newroot = NULL;
|
2009-06-24 17:28:13 +00:00
|
|
|
context = NULL;
|
2006-06-24 10:28:24 +00:00
|
|
|
device = NULL;
|
2006-06-11 13:05:41 +00:00
|
|
|
foreground = 0;
|
2008-08-07 21:18:15 +00:00
|
|
|
bind_enable = 0;
|
|
|
|
bind_fd = 0;
|
2009-12-29 20:00:57 +00:00
|
|
|
mtu = 1130; /* Very many relays give fragsize 1150 or slightly
|
|
|
|
higher for NULL; tun/zlib adds ~17 bytes. */
|
2015-06-28 10:54:35 +00:00
|
|
|
listen_ip4 = NULL;
|
2015-06-28 18:01:48 +00:00
|
|
|
listen_ip6 = NULL;
|
2006-11-05 13:18:57 +00:00
|
|
|
port = 53;
|
2012-09-03 08:34:27 +00:00
|
|
|
ns_get_externalip = 0;
|
2015-06-30 19:32:21 +00:00
|
|
|
addrfamily = AF_UNSPEC;
|
2008-07-12 11:45:22 +00:00
|
|
|
skipipconfig = 0;
|
2009-08-15 21:52:49 +00:00
|
|
|
pidfile = NULL;
|
2015-08-21 08:57:54 +00:00
|
|
|
srand(time(NULL));
|
2014-06-01 06:34:18 +00:00
|
|
|
|
2009-06-24 16:40:51 +00:00
|
|
|
retval = 0;
|
|
|
|
|
2015-08-21 15:23:24 +00:00
|
|
|
server_init();
|
|
|
|
|
2009-01-25 17:16:00 +00:00
|
|
|
#ifdef WINDOWS32
|
|
|
|
WSAStartup(req_version, &wsa_data);
|
|
|
|
#endif
|
2007-06-09 16:18:59 +00:00
|
|
|
|
2008-07-12 12:26:41 +00:00
|
|
|
#if !defined(BSD) && !defined(__GLIBC__)
|
|
|
|
__progname = strrchr(argv[0], '/');
|
|
|
|
if (__progname == NULL)
|
|
|
|
__progname = argv[0];
|
|
|
|
else
|
|
|
|
__progname++;
|
|
|
|
#endif
|
|
|
|
|
2015-06-30 19:32:21 +00:00
|
|
|
while ((choice = getopt(argc, argv, "46vcsfhDu:t:d:m:l:L:p:n:b:P:z:F:i:")) != -1) {
|
2006-06-09 20:35:26 +00:00
|
|
|
switch(choice) {
|
2015-06-30 19:32:21 +00:00
|
|
|
case '4':
|
|
|
|
addrfamily = AF_INET;
|
|
|
|
break;
|
|
|
|
case '6':
|
|
|
|
addrfamily = AF_INET6;
|
|
|
|
break;
|
2006-06-11 13:27:48 +00:00
|
|
|
case 'v':
|
|
|
|
version();
|
|
|
|
break;
|
2008-07-12 22:39:29 +00:00
|
|
|
case 'c':
|
|
|
|
check_ip = 0;
|
|
|
|
break;
|
2008-07-12 11:45:22 +00:00
|
|
|
case 's':
|
|
|
|
skipipconfig = 1;
|
|
|
|
break;
|
2006-06-11 13:05:41 +00:00
|
|
|
case 'f':
|
|
|
|
foreground = 1;
|
|
|
|
break;
|
2006-06-11 13:14:57 +00:00
|
|
|
case 'h':
|
|
|
|
help();
|
|
|
|
break;
|
2008-08-05 22:37:40 +00:00
|
|
|
case 'D':
|
|
|
|
debug++;
|
|
|
|
break;
|
2006-06-09 20:35:26 +00:00
|
|
|
case 'u':
|
|
|
|
username = optarg;
|
|
|
|
break;
|
2006-06-11 14:29:36 +00:00
|
|
|
case 't':
|
|
|
|
newroot = optarg;
|
|
|
|
break;
|
2006-06-24 10:28:24 +00:00
|
|
|
case 'd':
|
|
|
|
device = optarg;
|
|
|
|
break;
|
2006-06-11 15:24:20 +00:00
|
|
|
case 'm':
|
|
|
|
mtu = atoi(optarg);
|
|
|
|
break;
|
2006-08-11 22:52:36 +00:00
|
|
|
case 'l':
|
2015-06-28 10:54:35 +00:00
|
|
|
listen_ip4 = optarg;
|
2006-08-11 22:52:36 +00:00
|
|
|
break;
|
2015-06-28 18:01:48 +00:00
|
|
|
case 'L':
|
|
|
|
listen_ip6 = optarg;
|
|
|
|
break;
|
2006-11-05 13:18:57 +00:00
|
|
|
case 'p':
|
|
|
|
port = atoi(optarg);
|
|
|
|
break;
|
2008-09-14 13:21:11 +00:00
|
|
|
case 'n':
|
2012-09-03 08:34:27 +00:00
|
|
|
if (optarg && strcmp("auto", optarg) == 0) {
|
|
|
|
ns_get_externalip = 1;
|
|
|
|
} else {
|
|
|
|
ns_ip = inet_addr(optarg);
|
|
|
|
}
|
2008-09-14 13:21:11 +00:00
|
|
|
break;
|
2008-08-07 21:18:15 +00:00
|
|
|
case 'b':
|
|
|
|
bind_enable = 1;
|
|
|
|
bind_port = atoi(optarg);
|
|
|
|
break;
|
2009-08-15 21:52:49 +00:00
|
|
|
case 'F':
|
|
|
|
pidfile = optarg;
|
2014-06-01 06:34:18 +00:00
|
|
|
break;
|
2013-12-23 20:58:28 +00:00
|
|
|
case 'i':
|
|
|
|
max_idle_time = atoi(optarg);
|
|
|
|
break;
|
2006-11-18 16:08:47 +00:00
|
|
|
case 'P':
|
2007-08-26 15:47:32 +00:00
|
|
|
strncpy(password, optarg, sizeof(password));
|
|
|
|
password[sizeof(password)-1] = 0;
|
2014-06-01 06:34:18 +00:00
|
|
|
|
2007-07-12 13:46:58 +00:00
|
|
|
/* XXX: find better way of cleaning up ps(1) */
|
2014-06-01 06:34:18 +00:00
|
|
|
memset(optarg, 0, strlen(optarg));
|
2006-11-18 16:08:47 +00:00
|
|
|
break;
|
2009-06-24 17:28:13 +00:00
|
|
|
case 'z':
|
|
|
|
context = optarg;
|
|
|
|
break;
|
2006-06-09 20:35:26 +00:00
|
|
|
default:
|
|
|
|
usage();
|
2006-06-11 14:33:59 +00:00
|
|
|
break;
|
2006-06-09 20:35:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
2007-02-04 20:37:36 +00:00
|
|
|
|
2009-01-24 15:50:54 +00:00
|
|
|
check_superuser(usage);
|
2006-06-05 18:47:09 +00:00
|
|
|
|
2014-06-01 06:34:18 +00:00
|
|
|
if (argc != 2)
|
2006-06-09 20:35:26 +00:00
|
|
|
usage();
|
2014-06-01 06:34:18 +00:00
|
|
|
|
2009-01-04 12:39:28 +00:00
|
|
|
netsize = strchr(argv[0], '/');
|
|
|
|
if (netsize) {
|
|
|
|
*netsize = 0;
|
|
|
|
netsize++;
|
|
|
|
netmask = atoi(netsize);
|
|
|
|
}
|
|
|
|
|
2008-09-14 13:21:11 +00:00
|
|
|
my_ip = inet_addr(argv[0]);
|
2014-06-01 06:34:18 +00:00
|
|
|
|
2008-09-14 13:21:11 +00:00
|
|
|
if (my_ip == INADDR_NONE) {
|
2009-07-16 08:44:04 +00:00
|
|
|
warnx("Bad IP address to use inside tunnel.");
|
2008-09-14 13:21:11 +00:00
|
|
|
usage();
|
|
|
|
}
|
2006-06-05 18:47:09 +00:00
|
|
|
|
2007-02-04 20:37:36 +00:00
|
|
|
topdomain = strdup(argv[1]);
|
2014-05-31 08:06:44 +00:00
|
|
|
if(check_topdomain(topdomain, &errormsg)) {
|
|
|
|
warnx("Invalid topdomain: %s", errormsg);
|
2007-07-11 23:25:03 +00:00
|
|
|
usage();
|
2014-05-31 08:06:44 +00:00
|
|
|
/* NOTREACHED */
|
2007-07-11 23:25:03 +00:00
|
|
|
}
|
2007-02-04 20:37:36 +00:00
|
|
|
|
2007-07-12 15:48:05 +00:00
|
|
|
if (username != NULL) {
|
2009-01-24 22:19:11 +00:00
|
|
|
#ifndef WINDOWS32
|
2007-07-12 15:48:05 +00:00
|
|
|
if ((pw = getpwnam(username)) == NULL) {
|
2009-07-16 08:44:04 +00:00
|
|
|
warnx("User %s does not exist!", username);
|
2006-06-11 12:18:49 +00:00
|
|
|
usage();
|
|
|
|
}
|
2009-01-24 22:19:11 +00:00
|
|
|
#endif
|
2006-06-11 12:18:49 +00:00
|
|
|
}
|
|
|
|
|
2008-07-12 11:41:01 +00:00
|
|
|
if (mtu <= 0) {
|
2009-07-16 08:44:04 +00:00
|
|
|
warnx("Bad MTU given.");
|
2006-06-11 15:24:20 +00:00
|
|
|
usage();
|
|
|
|
}
|
2014-06-01 06:34:18 +00:00
|
|
|
|
2008-07-12 11:41:01 +00:00
|
|
|
if(port < 1 || port > 65535) {
|
2009-07-16 08:44:04 +00:00
|
|
|
warnx("Bad port number given.");
|
2008-07-12 11:41:01 +00:00
|
|
|
usage();
|
|
|
|
}
|
2014-06-01 06:34:18 +00:00
|
|
|
|
2014-02-05 21:36:53 +00:00
|
|
|
if (port != 53) {
|
|
|
|
fprintf(stderr, "ALERT! Other dns servers expect you to run on port 53.\n");
|
|
|
|
fprintf(stderr, "You must manually forward port 53 to port %d for things to work.\n", port);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (debug) {
|
|
|
|
fprintf(stderr, "Debug level %d enabled, will stay in foreground.\n", debug);
|
|
|
|
fprintf(stderr, "Add more -D switches to set higher debug level.\n");
|
|
|
|
foreground = 1;
|
|
|
|
}
|
|
|
|
|
2015-06-28 10:54:35 +00:00
|
|
|
dns4addr_len = get_addr(listen_ip4, port, AF_INET, AI_PASSIVE | AI_NUMERICHOST, &dns4addr);
|
|
|
|
if (dns4addr_len < 0) {
|
2015-06-28 18:01:48 +00:00
|
|
|
warnx("Bad IPv4 address to listen on.");
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
dns6addr_len = get_addr(listen_ip6, port, AF_INET6, AI_PASSIVE | AI_NUMERICHOST, &dns6addr);
|
|
|
|
if (dns6addr_len < 0) {
|
|
|
|
warnx("Bad IPv6 address to listen on.");
|
2014-02-05 21:36:53 +00:00
|
|
|
usage();
|
|
|
|
}
|
|
|
|
|
2008-08-07 21:18:15 +00:00
|
|
|
if(bind_enable) {
|
2015-06-28 10:54:35 +00:00
|
|
|
in_addr_t dns_ip = ((struct sockaddr_in *) &dns4addr)->sin_addr.s_addr;
|
2009-07-16 08:44:04 +00:00
|
|
|
if (bind_port < 1 || bind_port > 65535) {
|
|
|
|
warnx("Bad DNS server port number given.");
|
|
|
|
usage();
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
/* Avoid forwarding loops */
|
2014-02-05 21:36:53 +00:00
|
|
|
if (bind_port == port && (dns_ip == INADDR_ANY || dns_ip == htonl(0x7f000001L))) {
|
2009-07-16 08:44:04 +00:00
|
|
|
warnx("Forward port is same as listen port (%d), will create a loop!", bind_port);
|
|
|
|
fprintf(stderr, "Use -l to set listen ip to avoid this.\n");
|
2008-08-07 21:18:15 +00:00
|
|
|
usage();
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
2009-02-28 14:35:03 +00:00
|
|
|
fprintf(stderr, "Requests for domains outside of %s will be forwarded to port %d\n",
|
2008-08-07 21:18:15 +00:00
|
|
|
topdomain, bind_port);
|
|
|
|
}
|
2006-06-11 15:24:20 +00:00
|
|
|
|
2012-09-03 08:34:27 +00:00
|
|
|
if (ns_get_externalip) {
|
|
|
|
struct in_addr extip;
|
|
|
|
int res = get_external_ip(&extip);
|
|
|
|
if (res) {
|
|
|
|
fprintf(stderr, "Failed to get external IP via web service.\n");
|
|
|
|
exit(3);
|
|
|
|
}
|
|
|
|
ns_ip = extip.s_addr;
|
|
|
|
fprintf(stderr, "Using %s as external IP.\n", inet_ntoa(extip));
|
|
|
|
}
|
|
|
|
|
2008-09-14 13:21:11 +00:00
|
|
|
if (ns_ip == INADDR_NONE) {
|
2009-07-16 08:44:04 +00:00
|
|
|
warnx("Bad IP address to return as nameserver.");
|
2008-09-14 13:21:11 +00:00
|
|
|
usage();
|
|
|
|
}
|
2009-01-04 12:03:35 +00:00
|
|
|
if (netmask > 30 || netmask < 8) {
|
2009-07-16 08:44:04 +00:00
|
|
|
warnx("Bad netmask (%d bits). Use 8-30 bits.", netmask);
|
2009-01-04 12:03:35 +00:00
|
|
|
usage();
|
|
|
|
}
|
2014-06-01 06:34:18 +00:00
|
|
|
|
2009-09-19 08:09:12 +00:00
|
|
|
if (strlen(password) == 0) {
|
|
|
|
if (NULL != getenv(PASSWORD_ENV_VAR))
|
|
|
|
snprintf(password, sizeof(password), "%s", getenv(PASSWORD_ENV_VAR));
|
|
|
|
else
|
|
|
|
read_password(password, sizeof(password));
|
|
|
|
}
|
2006-11-18 16:08:47 +00:00
|
|
|
|
2015-06-28 19:05:23 +00:00
|
|
|
/* Mark both file descriptors as unused */
|
|
|
|
dns_fds.v4fd = -1;
|
|
|
|
dns_fds.v6fd = -1;
|
|
|
|
|
2010-02-08 16:50:45 +00:00
|
|
|
created_users = init_users(my_ip, netmask);
|
|
|
|
|
2009-06-24 16:40:51 +00:00
|
|
|
if ((tun_fd = open_tun(device)) == -1) {
|
2015-06-28 19:05:23 +00:00
|
|
|
/* nothing to clean up, just return */
|
|
|
|
return 1;
|
2009-06-24 16:40:51 +00:00
|
|
|
}
|
|
|
|
if (!skipipconfig) {
|
2010-03-01 22:05:55 +00:00
|
|
|
const char *other_ip = users_get_first_ip();
|
|
|
|
if (tun_setip(argv[0], other_ip, netmask) != 0 || tun_setmtu(mtu) != 0) {
|
2009-06-24 16:40:51 +00:00
|
|
|
retval = 1;
|
2010-03-01 22:05:55 +00:00
|
|
|
free((void*) other_ip);
|
2015-06-28 19:05:23 +00:00
|
|
|
goto cleanup;
|
2009-06-24 16:40:51 +00:00
|
|
|
}
|
2010-03-01 22:05:55 +00:00
|
|
|
free((void*) other_ip);
|
2009-06-24 16:40:51 +00:00
|
|
|
}
|
2015-06-28 10:54:35 +00:00
|
|
|
|
2013-12-23 09:48:46 +00:00
|
|
|
#ifdef HAVE_SYSTEMD
|
|
|
|
nb_fds = sd_listen_fds(0);
|
|
|
|
if (nb_fds > 1) {
|
2009-06-24 16:40:51 +00:00
|
|
|
retval = 1;
|
2013-12-23 09:48:46 +00:00
|
|
|
warnx("Too many file descriptors received!\n");
|
2015-06-28 19:05:23 +00:00
|
|
|
goto cleanup;
|
2013-12-23 09:48:46 +00:00
|
|
|
} else if (nb_fds == 1) {
|
2015-06-28 10:54:35 +00:00
|
|
|
/* XXX: assume we get IPv4 socket */
|
|
|
|
dns_fds.v4fd = SD_LISTEN_FDS_START;
|
2013-12-23 09:48:46 +00:00
|
|
|
} else {
|
|
|
|
#endif
|
2015-06-30 19:32:21 +00:00
|
|
|
if ((addrfamily == AF_UNSPEC || addrfamily == AF_INET) &&
|
|
|
|
(dns_fds.v4fd = open_dns(&dns4addr, dns4addr_len)) < 0) {
|
|
|
|
|
2013-12-23 09:48:46 +00:00
|
|
|
retval = 1;
|
2015-06-28 19:05:23 +00:00
|
|
|
goto cleanup;
|
2013-12-23 09:48:46 +00:00
|
|
|
}
|
2015-06-30 19:32:21 +00:00
|
|
|
if ((addrfamily == AF_UNSPEC || addrfamily == AF_INET6) &&
|
2015-06-30 19:56:11 +00:00
|
|
|
/* Set IPv6 socket to V6ONLY */
|
|
|
|
(dns_fds.v6fd = open_dns_opt(&dns6addr, dns6addr_len, 1)) < 0) {
|
|
|
|
|
2015-06-28 18:01:48 +00:00
|
|
|
retval = 1;
|
2015-06-28 19:05:23 +00:00
|
|
|
goto cleanup;
|
2015-06-28 18:01:48 +00:00
|
|
|
}
|
2013-12-23 09:48:46 +00:00
|
|
|
#ifdef HAVE_SYSTEMD
|
2009-06-24 16:40:51 +00:00
|
|
|
}
|
2013-12-23 09:48:46 +00:00
|
|
|
#endif
|
2015-06-28 20:41:54 +00:00
|
|
|
|
|
|
|
/* Setup dns file descriptors to get destination IP address */
|
|
|
|
if (dns_fds.v4fd >= 0)
|
|
|
|
prepare_dns_fd(dns_fds.v4fd);
|
|
|
|
if (dns_fds.v6fd >= 0)
|
|
|
|
prepare_dns_fd(dns_fds.v6fd);
|
|
|
|
|
2009-06-24 16:40:51 +00:00
|
|
|
if (bind_enable) {
|
2014-02-05 21:36:53 +00:00
|
|
|
if ((bind_fd = open_dns_from_host(NULL, 0, AF_INET, 0)) < 0) {
|
2009-06-24 16:40:51 +00:00
|
|
|
retval = 1;
|
2015-06-28 19:05:23 +00:00
|
|
|
goto cleanup;
|
2009-06-24 16:40:51 +00:00
|
|
|
}
|
|
|
|
}
|
2006-06-23 07:58:36 +00:00
|
|
|
|
|
|
|
my_mtu = mtu;
|
2014-06-01 06:34:18 +00:00
|
|
|
|
2009-01-04 12:03:35 +00:00
|
|
|
if (created_users < USERS) {
|
2009-02-28 14:35:03 +00:00
|
|
|
fprintf(stderr, "Limiting to %d simultaneous users because of netmask /%d\n",
|
2009-01-04 12:03:35 +00:00
|
|
|
created_users, netmask);
|
|
|
|
}
|
2009-02-28 14:35:03 +00:00
|
|
|
fprintf(stderr, "Listening to dns for domain %s\n", topdomain);
|
2006-06-11 14:42:19 +00:00
|
|
|
|
2014-06-01 06:34:18 +00:00
|
|
|
if (foreground == 0)
|
2007-11-27 20:11:43 +00:00
|
|
|
do_detach();
|
2014-06-01 06:34:18 +00:00
|
|
|
|
2009-08-15 21:52:49 +00:00
|
|
|
if (pidfile != NULL)
|
|
|
|
do_pidfile(pidfile);
|
|
|
|
|
2010-02-08 16:09:45 +00:00
|
|
|
#ifdef FREEBSD
|
|
|
|
tzsetwall();
|
|
|
|
#endif
|
2010-02-08 16:13:17 +00:00
|
|
|
#ifndef WINDOWS32
|
2010-02-08 16:09:45 +00:00
|
|
|
openlog( __progname, LOG_NDELAY, LOG_DAEMON );
|
2010-02-08 16:13:17 +00:00
|
|
|
#endif
|
2010-02-08 16:09:45 +00:00
|
|
|
|
2007-07-12 13:36:24 +00:00
|
|
|
if (newroot != NULL)
|
|
|
|
do_chroot(newroot);
|
2006-06-11 13:05:41 +00:00
|
|
|
|
2006-06-05 18:47:09 +00:00
|
|
|
signal(SIGINT, sigint);
|
2007-07-12 15:48:05 +00:00
|
|
|
if (username != NULL) {
|
2009-01-24 22:19:11 +00:00
|
|
|
#ifndef WINDOWS32
|
2008-07-12 12:05:59 +00:00
|
|
|
gid_t gids[1];
|
|
|
|
gids[0] = pw->pw_gid;
|
|
|
|
if (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
|
2007-07-12 15:48:05 +00:00
|
|
|
warnx("Could not switch to user %s!\n", username);
|
2006-06-09 20:35:26 +00:00
|
|
|
usage();
|
|
|
|
}
|
2009-01-24 22:19:11 +00:00
|
|
|
#endif
|
2006-06-09 20:35:26 +00:00
|
|
|
}
|
2009-02-15 18:24:12 +00:00
|
|
|
|
2009-06-24 17:28:13 +00:00
|
|
|
if (context != NULL)
|
|
|
|
do_setcon(context);
|
|
|
|
|
2009-02-15 18:24:12 +00:00
|
|
|
syslog(LOG_INFO, "started, listening on port %d", port);
|
2014-06-01 06:34:18 +00:00
|
|
|
|
2015-08-21 08:57:54 +00:00
|
|
|
server_tunnel(tun_fd, &dns_fds, bind_fd, max_idle_time);
|
2006-06-05 18:47:09 +00:00
|
|
|
|
2009-02-15 18:24:12 +00:00
|
|
|
syslog(LOG_INFO, "stopping");
|
2008-08-07 21:18:15 +00:00
|
|
|
close_dns(bind_fd);
|
2015-06-28 19:05:23 +00:00
|
|
|
cleanup:
|
2015-06-28 18:01:48 +00:00
|
|
|
if (dns_fds.v6fd >= 0)
|
|
|
|
close_dns(dns_fds.v6fd);
|
2015-06-28 10:54:35 +00:00
|
|
|
if (dns_fds.v4fd >= 0)
|
|
|
|
close_dns(dns_fds.v4fd);
|
2014-06-01 06:34:18 +00:00
|
|
|
close_tun(tun_fd);
|
2006-06-05 18:47:09 +00:00
|
|
|
|
2009-06-24 16:40:51 +00:00
|
|
|
return retval;
|
2006-06-05 18:47:09 +00:00
|
|
|
}
|