示例#1
0
文件: tun.c 项目: ypid/andiodine
DWORD WINAPI tun_reader(LPVOID arg)
{
	struct tun_data *tun = arg;
	char buf[64*1024];
	int len;
	int res;
	OVERLAPPED olpd;
	int sock;

	sock = open_dns(0, INADDR_ANY);

	olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

	while(TRUE) {
		olpd.Offset = 0;
		olpd.OffsetHigh = 0;
		res = ReadFile(tun->tun, buf, sizeof(buf), (LPDWORD) &len, &olpd);
		if (!res) {
			WaitForSingleObject(olpd.hEvent, INFINITE);
			res = GetOverlappedResult(dev_handle, &olpd, (LPDWORD) &len, FALSE);
			res = sendto(sock, buf, len, 0, (struct sockaddr*) &(tun->addr), 
				sizeof(struct sockaddr_in));
		}
	}

	return 0;
}
示例#2
0
文件: common.c 项目: AgentT/iodine
int
open_dns_from_host(char *host, int port, int addr_family, int flags)
{
	struct sockaddr_storage addr;
	int addrlen;

	addrlen = get_addr(host, port, addr_family, flags, &addr);
	if (addrlen < 0)
		return addrlen;

	return open_dns(&addr, addrlen);
}
示例#3
0
文件: tun.c 项目: ypid/andiodine
int 
open_tun(const char *tun_device) 
{
	char adapter[256];
	char tapfile[512];
	int tunfd;
	in_addr_t local;

	memset(adapter, 0, sizeof(adapter));
	memset(if_name, 0, sizeof(if_name));
	get_device(adapter, sizeof(adapter), tun_device);

	if (strlen(adapter) == 0 || strlen(if_name) == 0) {
		if (tun_device) {
			warnx("No TAP adapters found. Try without -d.");
		} else {
			warnx("No TAP adapters found. Version 0801 and 0901 are supported.");
		}
		return -1;
	}
	
	fprintf(stderr, "Opening device %s\n", if_name);
	snprintf(tapfile, sizeof(tapfile), "%s%s.tap", TAP_DEVICE_SPACE, adapter);
	dev_handle = CreateFile(tapfile, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL);
	if (dev_handle == INVALID_HANDLE_VALUE) {
		warnx("Could not open device!");
		return -1;
	}

	/* Use a UDP connection to forward packets from tun,
	 * so we can still use select() in main code.
	 * A thread does blocking reads on tun device and 
	 * sends data as udp to this socket */
	
	local = htonl(0x7f000001); /* 127.0.0.1 */
	tunfd = open_dns(55353, local);

	data.tun = dev_handle;
	memset(&(data.addr), 0, sizeof(data.addr));
	data.addr.sin_family = AF_INET;
	data.addr.sin_port = htons(55353);
	data.addr.sin_addr.s_addr = local;
	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tun_reader, &data, 0, NULL);
	
	return tunfd;
}
示例#4
0
int
main(int argc, char **argv)
{
	extern char *__progname;
	char *listen_ip4;
	char *listen_ip6;
	char *errormsg;
#ifndef WINDOWS32
	struct passwd *pw = NULL;
#endif
	int foreground;
	char *username;
	char *newroot;
	char *context;
	char *device;
	char *pidfile;

	int choice;

	int skipipconfig;
	char *netsize;
	int ns_get_externalip;
	int retval;

#ifdef HAVE_SYSTEMD
	int nb_fds;
#endif

	errormsg = NULL;
	username = NULL;
	newroot = NULL;
	context = NULL;
	device = NULL;
	foreground = 0;
	listen_ip4 = NULL;
	listen_ip6 = NULL;

	ns_get_externalip = 0;
	skipipconfig = 0;
	pidfile = NULL;
	srand(time(NULL));

	retval = 0;

#ifdef WINDOWS32
	WSAStartup(req_version, &wsa_data);
#endif

#if !defined(BSD) && !defined(__GLIBC__)
	__progname = strrchr(argv[0], '/');
	if (__progname == NULL)
		__progname = argv[0];
	else
		__progname++;
#endif

	// Load default values from preset
	memcpy(&server, &preset_default, sizeof(struct server_instance));

	/* each option has format:
	   char *name, int has_arg, int *flag, int val */
	static struct option iodined_args[] = {
		{"version", no_argument, 0, 'v'},
		{"noipcheck", no_argument, 0, 'c'},
		{"notun", no_argument, 0, 's'},
		{"user", required_argument, 0, 'u'},
		{"listen4", required_argument, 0, 'l'},
		{"listen6", required_argument, 0, 'L'},
		{"nsip", required_argument, 0, 'n'},
		{"mtu", required_argument, 0, 'm'},
		{"idlequit", required_argument, 0, 'i'},
		{"forwardto", required_argument, 0, 'b'},
		{"localforward", no_argument, 0, 'A'},
		{"remoteforward", no_argument, 0, 'R'},
		{"help", no_argument, 0, 'h'},
		{"context", required_argument, 0, 'z'},
		{"chrootdir", required_argument, 0, 't'},
		{"pidfile", required_argument, 0, 'F'},
		{NULL, 0, 0, 0}
	};

	static char *iodined_args_short = "46vcsfhDARu:t:d:m:l:L:p:n:b:P:z:F:i:";

	server.running = 1;

	while ((choice = getopt_long(argc, argv, iodined_args_short, iodined_args, NULL)) != -1) {
		switch(choice) {
		case '4':
			server.addrfamily = AF_INET;
			break;
		case '6':
			server.addrfamily = AF_INET6;
			break;
		case 'v':
			version();
			break;
		case 'c':
			server.check_ip = 0;
			break;
		case 's':
			skipipconfig = 1;
			break;
		case 'f':
			foreground = 1;
			break;
		case 'h':
			help();
			break;
		case 'D':
			server.debug++;
			break;
		case 'u':
			username = optarg;
			break;
		case 't':
			newroot = optarg;
			break;
		case 'd':
			device = optarg;
			break;
		case 'm':
			server.mtu = atoi(optarg);
			break;
		case 'l':
			listen_ip4 = optarg;
			break;
		case 'L':
			listen_ip6 = optarg;
			break;
		case 'p':
			server.port = atoi(optarg);
			break;
		case 'n':
			if (optarg && strcmp("auto", optarg) == 0) {
				ns_get_externalip = 1;
			} else {
				server.ns_ip = inet_addr(optarg);
			}
			break;
		case 'b':
			server.bind_enable = 1;
			server.bind_port = atoi(optarg);
			break;
		case 'A':
			server.allow_forward_local_port = 1;
			break;
		case 'R':
			server.allow_forward_local_port = 1;
			server.allow_forward_remote = 1;
			break;
		case 'F':
			pidfile = optarg;
			break;
		case 'i':
			server.max_idle_time = atoi(optarg);
			break;
		case 'P':
			strncpy(server.password, optarg, sizeof(server.password));
			server.password[sizeof(server.password)-1] = 0;

			/* XXX: find better way of cleaning up ps(1) */
			memset(optarg, 0, strlen(optarg));
			break;
		case 'z':
			context = optarg;
			break;
		default:
			usage();
			break;
		}
	}

	argc -= optind;
	argv += optind;

	check_superuser(usage);

	if (argc != 2)
		usage();

	netsize = strchr(argv[0], '/');
	if (netsize) {
		*netsize = 0;
		netsize++;
		server.netmask = atoi(netsize);
	}

	server.my_ip = inet_addr(argv[0]);

	if (server.my_ip == INADDR_NONE) {
		warnx("Bad IP address to use inside tunnel.");
		usage();
	}

	server.topdomain = strdup(argv[1]);
	if(check_topdomain(server.topdomain, &errormsg)) {
		warnx("Invalid topdomain: %s", errormsg);
		usage();
		/* NOTREACHED */
	}

	if (username != NULL) {
#ifndef WINDOWS32
		if ((pw = getpwnam(username)) == NULL) {
			warnx("User %s does not exist!", username);
			usage();
		}
#endif
	}

	if (server.mtu <= 0) {
		warnx("Bad MTU given.");
		usage();
	}

	if(server.port < 1 || server.port > 65535) {
		warnx("Bad port number given.");
		usage();
	}

	if (server.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", server.port);
	}

	if (server.debug) {
		fprintf(stderr, "Debug level %d enabled, will stay in foreground.\n", server.debug);
		fprintf(stderr, "Add more -D switches to set higher debug level.\n");
		foreground = 1;
	}

	if (server.addrfamily == AF_UNSPEC || server.addrfamily == AF_INET) {
		server.dns4addr_len = get_addr(listen_ip4, server.port, AF_INET,
									   AI_PASSIVE | AI_NUMERICHOST, &server.dns4addr);
		if (server.dns4addr_len < 0) {
			warnx("Bad IPv4 address to listen on.");
			usage();
		}
	}
	if (server.addrfamily == AF_UNSPEC || server.addrfamily == AF_INET6) {
		server.dns6addr_len = get_addr(listen_ip6, server.port, AF_INET6,
									   AI_PASSIVE | AI_NUMERICHOST, &server.dns6addr);
		if (server.dns6addr_len < 0) {
			warnx("Bad IPv6 address to listen on.");
			usage();
		}
	}
	if (server.bind_enable) {
		in_addr_t dns_ip = ((struct sockaddr_in *) &server.dns4addr)->sin_addr.s_addr;
		if (server.bind_port < 1 || server.bind_port > 65535) {
			warnx("Bad DNS server port number given.");
			usage();
			/* NOTREACHED */
		}
		/* Avoid forwarding loops */
		if (server.bind_port == server.port && (dns_ip == INADDR_ANY || dns_ip == INADDR_LOOPBACK)) {
			warnx("Forward port is same as listen port (%d), will create a loop!", server.bind_port);
			fprintf(stderr, "Use -l to set listen ip to avoid this.\n");
			usage();
			/* NOTREACHED */
		}
		fprintf(stderr, "Requests for domains outside of %s will be forwarded to port %d\n",
				server.topdomain, server.bind_port);
	}

	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);
		}
		server.ns_ip = extip.s_addr;
		fprintf(stderr, "Using %s as external IP.\n", inet_ntoa(extip));
	}

	if (server.ns_ip == INADDR_NONE) {
		warnx("Bad IP address to return as nameserver.");
		usage();
	}
	if (server.netmask > 30 || server.netmask < 8) {
		warnx("Bad netmask (%d bits). Use 8-30 bits.", server.netmask);
		usage();
	}

	if (strlen(server.password) == 0) {
		if (NULL != getenv(PASSWORD_ENV_VAR))
			snprintf(server.password, sizeof(server.password), "%s", getenv(PASSWORD_ENV_VAR));
		else
			read_password(server.password, sizeof(server.password));
	}

	created_users = init_users(server.my_ip, server.netmask);

	if ((server.tun_fd = open_tun(device)) == -1) {
		/* nothing to clean up, just return */
		return 1;
	}
	if (!skipipconfig) {
		const char *other_ip = users_get_first_ip();
		if (tun_setip(argv[0], other_ip, server.netmask) != 0 || tun_setmtu(server.mtu) != 0) {
			retval = 1;
			free((void*) other_ip);
			goto cleanup;
		}
		free((void*) other_ip);
	}

#ifdef HAVE_SYSTEMD
	nb_fds = sd_listen_fds(0);
	if (nb_fds > 1) {
		retval = 1;
		warnx("Too many file descriptors received!\n");
		goto cleanup;
	} else if (nb_fds == 1) {
		/* XXX: assume we get IPv4 socket */
		server.dns_fds.v4fd = SD_LISTEN_FDS_START;
	} else {
#endif
		if ((server.addrfamily == AF_UNSPEC || server.addrfamily == AF_INET) &&
			(server.dns_fds.v4fd = open_dns(&server.dns4addr, server.dns4addr_len)) < 0) {

			retval = 1;
			goto cleanup;
		}
		if ((server.addrfamily == AF_UNSPEC || server.addrfamily == AF_INET6) &&
			/* Set IPv6 socket to V6ONLY */
			(server.dns_fds.v6fd = open_dns_opt(&server.dns6addr, server.dns6addr_len, 1)) < 0) {

			retval = 1;
			goto cleanup;
		}
#ifdef HAVE_SYSTEMD
	}
#endif

	/* Setup dns file descriptors to get destination IP address */
	if (server.dns_fds.v4fd >= 0)
		prepare_dns_fd(server.dns_fds.v4fd);
	if (server.dns_fds.v6fd >= 0)
		prepare_dns_fd(server.dns_fds.v6fd);

	if (server.bind_enable) {
		if ((server.bind_fd = open_dns_from_host(NULL, 0, AF_INET, 0)) < 0) {
			retval = 1;
			goto cleanup;
		}
	}

	if (created_users < USERS) {
		fprintf(stderr, "Limiting to %d simultaneous users because of netmask /%d\n",
			created_users, server.netmask);
	}
	fprintf(stderr, "Listening to dns for domain %s\n", server.topdomain);

	if (foreground == 0)
		do_detach();

	if (pidfile != NULL)
		do_pidfile(pidfile);

#ifdef FREEBSD
	tzsetwall();
#endif
#ifndef WINDOWS32
	openlog( __progname, LOG_NDELAY, LOG_DAEMON );
#endif

	if (newroot != NULL)
		do_chroot(newroot);

	signal(SIGINT, sigint);
	if (username != NULL) {
#ifndef WINDOWS32
		gid_t gids[1];
		gids[0] = pw->pw_gid;
		if (setgroups(1, gids) < 0 || setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
			warnx("Could not switch to user %s!\n", username);
			usage();
		}
#endif
	}

	if (context != NULL)
		do_setcon(context);

	syslog(LOG_INFO, "started, listening on port %d", server.port);

	server_tunnel();

	syslog(LOG_INFO, "stopping");
	close_socket(server.bind_fd);
cleanup:
	close_socket(server.dns_fds.v6fd);
	close_socket(server.dns_fds.v4fd);
	close_socket(server.tun_fd);
#ifdef WINDOWS32
	WSACleanup();
#endif
	/* TODO close user TCP forward sockets */

	return retval;
}