mirror of
				https://github.com/yarrick/iodine.git
				synced 2025-10-30 21:58:40 +00:00 
			
		
		
		
	Refactor client code to use client_instance
This commit is contained in:
		
							
								
								
									
										953
									
								
								src/client.c
									
									
									
									
									
								
							
							
						
						
									
										953
									
								
								src/client.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										125
									
								
								src/client.h
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								src/client.h
									
									
									
									
									
								
							| @@ -23,13 +23,124 @@ | |||||||
| extern int debug; | extern int debug; | ||||||
| extern int stats; | extern int stats; | ||||||
|  |  | ||||||
| #define PENDING_QUERIES_LENGTH (MAX(windowsize_up, windowsize_down) * 3) | #define PENDING_QUERIES_LENGTH (MAX(this.windowsize_up, this.windowsize_down) * 4) | ||||||
|  | #define INSTANCE this | ||||||
|  |  | ||||||
|  | struct client_instance { | ||||||
|  | 	int max_downstream_frag_size; | ||||||
|  | 	int autodetect_frag_size; | ||||||
|  | 	int hostname_maxlen; | ||||||
|  | 	int raw_mode; | ||||||
|  | 	int foreground; | ||||||
|  | 	char password[33]; | ||||||
|  |  | ||||||
|  | 	/* DNS nameserver info */ | ||||||
|  | 	char **nameserv_hosts; | ||||||
|  | 	size_t nameserv_hosts_len; | ||||||
|  | 	struct sockaddr_storage *nameserv_addrs; | ||||||
|  | 	size_t nameserv_addrs_len; | ||||||
|  | 	int current_nameserver; | ||||||
|  | 	struct sockaddr_storage raw_serv; | ||||||
|  | 	int raw_serv_len; | ||||||
|  | 	char *topdomain; | ||||||
|  |  | ||||||
|  | 	int tun_fd; | ||||||
|  | 	int dns_fd; | ||||||
|  |  | ||||||
|  | #ifdef OPENBSD | ||||||
|  | 	int rtable; | ||||||
|  | #endif | ||||||
|  | 	int running; | ||||||
|  |  | ||||||
|  | 	/* Output flags for debug and time between stats update */ | ||||||
|  | 	int debug; | ||||||
|  | 	int stats; | ||||||
|  |  | ||||||
|  | 	uint16_t rand_seed; | ||||||
|  |  | ||||||
|  | 	/* Current up/downstream window data */ | ||||||
|  | 	struct frag_buffer *outbuf; | ||||||
|  | 	struct frag_buffer *inbuf; | ||||||
|  | 	size_t windowsize_up; | ||||||
|  | 	size_t windowsize_down; | ||||||
|  | 	size_t maxfragsize_up; | ||||||
|  |  | ||||||
|  | 	/* Next downstream seqID to be ACK'd (-1 if none pending) */ | ||||||
|  | 	int next_downstream_ack; | ||||||
|  |  | ||||||
|  | 	/* Remembering queries we sent for tracking purposes */ | ||||||
|  | 	struct query_tuple *pending_queries; | ||||||
|  | 	size_t num_pending; | ||||||
|  | 	time_t max_timeout_ms; | ||||||
|  | 	time_t send_interval_ms; | ||||||
|  | 	time_t min_send_interval_ms; | ||||||
|  |  | ||||||
|  | 	/* Server response timeout in ms and downstream window timeout */ | ||||||
|  | 	time_t server_timeout_ms; | ||||||
|  | 	time_t downstream_timeout_ms; | ||||||
|  | 	int autodetect_server_timeout; | ||||||
|  |  | ||||||
|  | 	/* Cumulative Round-Trip-Time in ms */ | ||||||
|  | 	time_t rtt_total_ms; | ||||||
|  | 	size_t num_immediate; | ||||||
|  |  | ||||||
|  | 	/* Connection statistics */ | ||||||
|  | 	size_t num_timeouts; | ||||||
|  | 	size_t num_untracked; | ||||||
|  | 	size_t num_servfail; | ||||||
|  | 	size_t num_badip; | ||||||
|  | 	size_t num_sent; | ||||||
|  | 	size_t num_recv; | ||||||
|  | 	size_t send_query_sendcnt; | ||||||
|  | 	size_t send_query_recvcnt; | ||||||
|  | 	size_t num_frags_sent; | ||||||
|  | 	size_t num_frags_recv; | ||||||
|  | 	size_t num_pings; | ||||||
|  |  | ||||||
|  | 	/* My userid at the server */ | ||||||
|  | 	char userid; | ||||||
|  | 	char userid_char;		/* used when sending (lowercase) */ | ||||||
|  | 	char userid_char2;		/* also accepted when receiving (uppercase) */ | ||||||
|  |  | ||||||
|  | 	uint16_t chunkid; | ||||||
|  |  | ||||||
|  | 	/* Base32 encoder used for non-data packets and replies */ | ||||||
|  | 	struct encoder *b32; | ||||||
|  | 	/* Base64 etc encoders for replies */ | ||||||
|  | 	struct encoder *b64; | ||||||
|  | 	struct encoder *b64u; | ||||||
|  | 	struct encoder *b128; | ||||||
|  |  | ||||||
|  | 	/* The encoder used for data packets | ||||||
|  | 	 * Defaults to Base32, can be changed after handshake */ | ||||||
|  | 	struct encoder *dataenc; | ||||||
|  |  | ||||||
|  | 	/* Upstream/downstream compression flags */ | ||||||
|  | 	int compression_up; | ||||||
|  | 	int compression_down; | ||||||
|  |  | ||||||
|  | 	/* The encoder to use for downstream data */ | ||||||
|  | 	char downenc; | ||||||
|  |  | ||||||
|  | 	/* set query type to send */ | ||||||
|  | 	uint16_t do_qtype; | ||||||
|  |  | ||||||
|  | 	/* My connection mode */ | ||||||
|  | 	enum connection conn; | ||||||
|  | 	int connected; | ||||||
|  |  | ||||||
|  | 	int lazymode; | ||||||
|  | 	long send_ping_soon; | ||||||
|  | 	time_t lastdownstreamtime; | ||||||
|  | }; | ||||||
|  |  | ||||||
| struct query_tuple { | struct query_tuple { | ||||||
| 	int id; /* DNS query / response ID */ | 	int id; /* DNS query / response ID */ | ||||||
| 	struct timeval time; /* time sent or 0 if cleared */ | 	struct timeval time; /* time sent or 0 if cleared */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | extern struct client_instance this; | ||||||
|  |  | ||||||
| void client_init(); | void client_init(); | ||||||
| void client_stop(); | void client_stop(); | ||||||
|  |  | ||||||
| @@ -37,18 +148,10 @@ enum connection client_get_conn(); | |||||||
| const char *client_get_raw_addr(); | const char *client_get_raw_addr(); | ||||||
|  |  | ||||||
| void client_rotate_nameserver(); | void client_rotate_nameserver(); | ||||||
| void client_set_nameservers(struct sockaddr_storage *, int); |  | ||||||
| void client_set_topdomain(const char *cp); |  | ||||||
| void client_set_password(const char *cp); |  | ||||||
| int client_set_qtype(char *qtype); | int client_set_qtype(char *qtype); | ||||||
| char *client_get_qtype(); | char *format_qtype(); | ||||||
| void client_set_downenc(char *encoding); | char parse_encoding(char *encoding); | ||||||
| void client_set_compression(int up, int down); |  | ||||||
| void client_set_dnstimeout(double, double, double, int); |  | ||||||
| void client_set_lazymode(int lazy_mode); |  | ||||||
| void client_set_windowsize(size_t, size_t); |  | ||||||
| void client_set_hostname_maxlen(size_t i); | void client_set_hostname_maxlen(size_t i); | ||||||
| void client_set_interval(double, double); |  | ||||||
|  |  | ||||||
| int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize); | int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize); | ||||||
| int client_tunnel(int tun_fd, int dns_fd); | int client_tunnel(int tun_fd, int dns_fd); | ||||||
|   | |||||||
							
								
								
									
										379
									
								
								src/iodine.c
									
									
									
									
									
								
							
							
						
						
									
										379
									
								
								src/iodine.c
									
									
									
									
									
								
							| @@ -21,6 +21,7 @@ | |||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <signal.h> | #include <signal.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
|  | #include <getopt.h> | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #include <sys/param.h> | #include <sys/param.h> | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
| @@ -40,6 +41,8 @@ | |||||||
| #include "tun.h" | #include "tun.h" | ||||||
| #include "client.h" | #include "client.h" | ||||||
| #include "util.h" | #include "util.h" | ||||||
|  | #include "encoding.h" | ||||||
|  | #include "base32.h" | ||||||
|  |  | ||||||
| #ifdef WINDOWS32 | #ifdef WINDOWS32 | ||||||
| WORD req_version = MAKEWORD(2, 2); | WORD req_version = MAKEWORD(2, 2); | ||||||
| @@ -52,10 +55,46 @@ static char *__progname; | |||||||
|  |  | ||||||
| #define PASSWORD_ENV_VAR "IODINE_PASS" | #define PASSWORD_ENV_VAR "IODINE_PASS" | ||||||
|  |  | ||||||
|  | struct client_instance this; | ||||||
|  |  | ||||||
|  | static struct client_instance preset_default = { | ||||||
|  | 	.foreground = 0, | ||||||
|  | #ifdef OPENBSD | ||||||
|  | 	.rtable = 0, | ||||||
|  | #endif | ||||||
|  | 	.debug = 0, | ||||||
|  | 	.stats = 0, | ||||||
|  | 	.raw_mode = 1, | ||||||
|  | 	.lazymode = 1, | ||||||
|  | 	.max_timeout_ms = 5000, | ||||||
|  | 	.send_interval_ms = 0, | ||||||
|  | 	.server_timeout_ms = 4000, | ||||||
|  | 	.downstream_timeout_ms = 2000, | ||||||
|  | 	.autodetect_server_timeout = 1, | ||||||
|  | 	.dataenc = &base32_encoder, | ||||||
|  | 	.autodetect_frag_size = 1, | ||||||
|  | 	.max_downstream_frag_size = MAX_FRAGSIZE, | ||||||
|  | 	.compression_up = 1, | ||||||
|  | 	.compression_down = 1, | ||||||
|  | 	.windowsize_up = 8, | ||||||
|  | 	.windowsize_down = 8, | ||||||
|  | 	.hostname_maxlen = 0xFF, | ||||||
|  |  | ||||||
|  | 	/* static startup values - should not be changed in presets */ | ||||||
|  | 	.conn = CONN_DNS_NULL, | ||||||
|  | 	.send_ping_soon = 1, | ||||||
|  | 	.downenc = ' ', | ||||||
|  | 	.do_qtype = T_UNSET, | ||||||
|  | 	.maxfragsize_up = 100, | ||||||
|  | 	.next_downstream_ack = -1, | ||||||
|  | 	.num_immediate = 1, | ||||||
|  | 	.rtt_total_ms = 200 | ||||||
|  | }; | ||||||
|  |  | ||||||
| static void | static void | ||||||
| sighandler(int sig) | sighandler(int sig) | ||||||
| { | { | ||||||
| 	client_stop(); | 	this.running = 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| #if defined(__GNUC__) || defined(__clang__) | #if defined(__GNUC__) || defined(__clang__) | ||||||
| @@ -69,7 +108,7 @@ print_usage() | |||||||
| { | { | ||||||
| 	extern char *__progname; | 	extern char *__progname; | ||||||
|  |  | ||||||
| 	fprintf(stderr, "Usage: %s [-v] [-h] [-V sec] [-f] [-r] [-u user] [-t chrootdir] [-d device] " | 	fprintf(stderr, "Usage: %s [-v] [-h] [-V sec] [-X port] [-f] [-r] [-u user] [-t chrootdir] [-d device] " | ||||||
| 			"[-w downfrags] [-W upfrags] [-i sec -j sec] [-I sec] [-c 0|1] [-C 0|1] [-s ms] " | 			"[-w downfrags] [-W upfrags] [-i sec -j sec] [-I sec] [-c 0|1] [-C 0|1] [-s ms] " | ||||||
| 			"[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-R rdomain] " | 			"[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-R rdomain] " | ||||||
| 			"[-z context] [-F pidfile] topdomain [nameserver1 [nameserver2 [...]]]\n", __progname); | 			"[-z context] [-F pidfile] topdomain [nameserver1 [nameserver2 [...]]]\n", __progname); | ||||||
| @@ -88,8 +127,8 @@ help() | |||||||
| 	fprintf(stderr, "iodine IP over DNS tunneling client\n"); | 	fprintf(stderr, "iodine IP over DNS tunneling client\n"); | ||||||
| 	print_usage(); | 	print_usage(); | ||||||
| 	fprintf(stderr, "\nOptions to try if connection doesn't work:\n"); | 	fprintf(stderr, "\nOptions to try if connection doesn't work:\n"); | ||||||
| 	fprintf(stderr, "  -T force dns type: NULL, PRIVATE, TXT, SRV, MX, CNAME, A (default: autodetect)\n"); | 	fprintf(stderr, "  -T  use DNS type: NULL, PRIVATE, TXT, SRV, MX, CNAME, A (default: autodetect)\n"); | ||||||
| 	fprintf(stderr, "  -O force downstream encoding for -T other than NULL: Base32, Base64, Base64u,\n"); | 	fprintf(stderr, "  -O  use specific downstream encoding for queries: Base32, Base64, Base64u,\n"); | ||||||
| 	fprintf(stderr, "        Base128, or (only for TXT:) Raw  (default: autodetect)\n"); | 	fprintf(stderr, "        Base128, or (only for TXT:) Raw  (default: autodetect)\n"); | ||||||
| 	fprintf(stderr, "  -I  target interval between sending and receiving requests (default: 4 secs)\n"); | 	fprintf(stderr, "  -I  target interval between sending and receiving requests (default: 4 secs)\n"); | ||||||
| 	fprintf(stderr, "        or ping interval in immediate mode (default: 1 sec)\n"); | 	fprintf(stderr, "        or ping interval in immediate mode (default: 1 sec)\n"); | ||||||
| @@ -97,7 +136,7 @@ help() | |||||||
| 	fprintf(stderr, "  -L 1: use lazy mode for low-latency (default). 0: don't (implies -I1)\n"); | 	fprintf(stderr, "  -L 1: use lazy mode for low-latency (default). 0: don't (implies -I1)\n"); | ||||||
| 	fprintf(stderr, "  -m  max size of downstream fragments (default: autodetect)\n"); | 	fprintf(stderr, "  -m  max size of downstream fragments (default: autodetect)\n"); | ||||||
| 	fprintf(stderr, "  -M  max size of upstream hostnames (~100-255, default: 255)\n"); | 	fprintf(stderr, "  -M  max size of upstream hostnames (~100-255, default: 255)\n"); | ||||||
| 	fprintf(stderr, "  -r to skip raw UDP mode attempt\n"); | 	fprintf(stderr, "  -r  skip raw UDP mode attempt\n"); | ||||||
| 	fprintf(stderr, "  -P  password used for authentication (max 32 chars will be used)\n\n"); | 	fprintf(stderr, "  -P  password used for authentication (max 32 chars will be used)\n\n"); | ||||||
|  |  | ||||||
| 	fprintf(stderr, "Fine-tuning options:\n"); | 	fprintf(stderr, "Fine-tuning options:\n"); | ||||||
| @@ -109,17 +148,20 @@ help() | |||||||
| 	fprintf(stderr, "  -C 1: use upstream compression (default), 0: disable\n\n"); | 	fprintf(stderr, "  -C 1: use upstream compression (default), 0: disable\n\n"); | ||||||
|  |  | ||||||
| 	fprintf(stderr, "Other options:\n"); | 	fprintf(stderr, "Other options:\n"); | ||||||
| 	fprintf(stderr, "  -v to print version info and exit\n"); | 	fprintf(stderr, "  -v, --version  print version info and exit\n"); | ||||||
| 	fprintf(stderr, "  -h to print this help and exit\n"); | 	fprintf(stderr, "  -h, --help  print this help and exit\n"); | ||||||
| 	fprintf(stderr, "  -V sec to print connection statistics at specified intervals\n"); | 	fprintf(stderr, "  -V, --stats  print connection statistics at given intervals (default: 5 sec)\n"); | ||||||
| 	fprintf(stderr, "  -f to keep running in foreground\n"); | 	fprintf(stderr, "  -X  skip tun device and forward data to/from stdin/out, telling the iodined to\n"); | ||||||
|  | 	fprintf(stderr, "        connect to the specified port listening on the server host.\n"); | ||||||
|  | 	fprintf(stderr, "        Can be used with SSH ProxyCommand option. (-X 22)\n"); | ||||||
|  | 	fprintf(stderr, "  -f  keep running in foreground\n"); | ||||||
| 	fprintf(stderr, "  -D  enable debug mode (add more D's to increase debug level)\n"); | 	fprintf(stderr, "  -D  enable debug mode (add more D's to increase debug level)\n"); | ||||||
| 	fprintf(stderr, "  -u name to drop privileges and run as user 'name'\n"); | 	fprintf(stderr, "  -d  set tunnel device name\n"); | ||||||
| 	fprintf(stderr, "  -t dir to chroot to directory dir\n"); | 	fprintf(stderr, "  -u  drop privileges and run as specified user\n"); | ||||||
| 	fprintf(stderr, "  -d device to set tunnel device name\n"); | 	fprintf(stderr, "  -F  write PID to specified file\n"); | ||||||
| 	fprintf(stderr, "  -z context, to apply specified SELinux context after initialization\n"); | 	fprintf(stderr, "  --chroot  chroot to given directory\n"); | ||||||
| 	fprintf(stderr, "  -R routing domain (OpenBSD only)\n"); | 	fprintf(stderr, "  --context  apply specified SELinux context after initialization\n"); | ||||||
| 	fprintf(stderr, "  -F pidfile to write pid to a file\n\n"); | 	fprintf(stderr, "  --rdomain  use specified routing domain (OpenBSD only)\n\n"); | ||||||
|  |  | ||||||
| 	fprintf(stderr, "nameserver is the IP/hostname of the relaying nameserver(s).\n"); | 	fprintf(stderr, "nameserver is the IP/hostname of the relaying nameserver(s).\n"); | ||||||
| 	fprintf(stderr, "   multiple nameservers can be specified (used in round-robin). \n"); | 	fprintf(stderr, "   multiple nameservers can be specified (used in round-robin). \n"); | ||||||
| @@ -140,96 +182,32 @@ version() | |||||||
| int | int | ||||||
| main(int argc, char **argv) | main(int argc, char **argv) | ||||||
| { | { | ||||||
| 	char *topdomain; | 	char *errormsg = NULL; | ||||||
| 	char *errormsg; |  | ||||||
| #ifndef WINDOWS32 | #ifndef WINDOWS32 | ||||||
| 	struct passwd *pw; | 	struct passwd *pw = NULL; | ||||||
| #endif | #endif | ||||||
| 	char *username; |  | ||||||
| 	char password[33]; |  | ||||||
| 	int foreground; |  | ||||||
| 	char *newroot; |  | ||||||
| 	char *context; |  | ||||||
| 	char *device; |  | ||||||
| 	char *pidfile; |  | ||||||
| 	int choice; | 	int choice; | ||||||
| 	int tun_fd; |  | ||||||
| 	int dns_fd; |  | ||||||
| 	int max_downstream_frag_size; |  | ||||||
| 	int autodetect_frag_size; |  | ||||||
| 	int hostname_maxlen; |  | ||||||
|  |  | ||||||
| 	int retval; | 	int retval; | ||||||
| 	int raw_mode; |  | ||||||
| 	int lazymode; |  | ||||||
| 	double target_interval_sec; |  | ||||||
| 	double server_timeout_sec; |  | ||||||
| 	double downstream_timeout_sec; |  | ||||||
| 	int min_interval_ms; |  | ||||||
| 	int autodetect_server_timeout; |  | ||||||
| 	int up_compression; |  | ||||||
| 	int down_compression; |  | ||||||
|  |  | ||||||
| 	int up_windowsize; | 	char *username = NULL; | ||||||
| 	int down_windowsize; | 	char *newroot = NULL; | ||||||
|  | 	char *context = NULL; | ||||||
|  | 	char *device = NULL; | ||||||
|  | 	char *pidfile = NULL; | ||||||
|  |  | ||||||
| #ifdef OPENBSD | 	char *nameserv_host = NULL; | ||||||
| 	int rtable = 0; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| 	char *nameserv_host; |  | ||||||
| 	char **nameserv_hosts; |  | ||||||
| 	int nameserv_hosts_len; |  | ||||||
| 	struct sockaddr_storage nameservaddr; | 	struct sockaddr_storage nameservaddr; | ||||||
| 	struct sockaddr_storage *nameserv_addrs; | 	int nameservaddr_len = 0; | ||||||
| 	size_t nameserv_addrs_len; | 	int nameserv_family = AF_UNSPEC; | ||||||
| 	int nameservaddr_len; |  | ||||||
| 	int nameserv_family; |  | ||||||
|  |  | ||||||
| 	/* Set default values */ |  | ||||||
| 	nameserv_addrs_len = 0; |  | ||||||
| 	nameservaddr_len = 0; |  | ||||||
| 	nameserv_host = NULL; |  | ||||||
| 	topdomain = NULL; |  | ||||||
| 	errormsg = NULL; |  | ||||||
| #ifndef WINDOWS32 |  | ||||||
| 	pw = NULL; |  | ||||||
| #endif |  | ||||||
| 	username = NULL; |  | ||||||
| 	memset(password, 0, 33); |  | ||||||
| 	srand(time(NULL)); |  | ||||||
| 	foreground = 0; |  | ||||||
| 	newroot = NULL; |  | ||||||
| 	context = NULL; |  | ||||||
| 	device = NULL; |  | ||||||
| 	pidfile = NULL; |  | ||||||
| 	debug = 0; |  | ||||||
| 	stats = 0; |  | ||||||
|  |  | ||||||
| 	autodetect_frag_size = 1; |  | ||||||
| 	max_downstream_frag_size = 3072; |  | ||||||
| 	retval = 0; |  | ||||||
| 	raw_mode = 1; |  | ||||||
| 	lazymode = 1; |  | ||||||
| 	target_interval_sec = 5;	/* DNS RFC says 5 seconds minimum */ |  | ||||||
| 	min_interval_ms = 0; |  | ||||||
| 	server_timeout_sec = 4;	/* Safe value for RTT <1s */ |  | ||||||
| 	downstream_timeout_sec = 2; |  | ||||||
| 	autodetect_server_timeout = 1; |  | ||||||
| 	hostname_maxlen = 0xFF; |  | ||||||
| 	nameserv_family = AF_UNSPEC; |  | ||||||
| 	up_compression = 1; |  | ||||||
| 	down_compression = 1; |  | ||||||
|  |  | ||||||
| 	up_windowsize = 8; |  | ||||||
| 	down_windowsize = 8; |  | ||||||
|  |  | ||||||
| #ifdef WINDOWS32 | #ifdef WINDOWS32 | ||||||
| 	WSAStartup(req_version, &wsa_data); | 	WSAStartup(req_version, &wsa_data); | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| 	srand((unsigned) time(NULL)); | 	srand((unsigned) time(NULL)); | ||||||
| 	client_init(); | 	this.rand_seed = (uint16_t) rand(); | ||||||
|  | 	this.chunkid = (uint16_t) rand(); | ||||||
|  | 	this.running = 1; | ||||||
|  |  | ||||||
| #if !defined(BSD) && !defined(__GLIBC__) | #if !defined(BSD) && !defined(__GLIBC__) | ||||||
| 	__progname = strrchr(argv[0], '/'); | 	__progname = strrchr(argv[0], '/'); | ||||||
| @@ -239,7 +217,23 @@ main(int argc, char **argv) | |||||||
| 		__progname++; | 		__progname++; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| 	while ((choice = getopt(argc, argv, "46vfDhrs:V:c:C:i:j:u:t:d:R:P:w:W:m:M:F:T:O:L:I:")) != -1) { | 	/* each option has format: | ||||||
|  | 	 * char *name, int has_arg, int *flag, int val */ | ||||||
|  | 	static struct option iodine_args[] = { | ||||||
|  | 		{"version", no_argument, 0, 'v'}, | ||||||
|  | 		{"help", no_argument, 0, 'h'}, | ||||||
|  | 		{"stats", optional_argument, 0, 'V'}, | ||||||
|  | 		{"context", required_argument, 0, 'z'}, | ||||||
|  | 		{"rdomain", required_argument, 0, 'R'}, | ||||||
|  | 		{"chrootdir", required_argument, 0, 't'}, | ||||||
|  | 		{"proxycommand", no_argument, 0, 'X'}, | ||||||
|  | 		{NULL, 0, 0, 0} | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	static char *iodine_args_short = "46vfDhrXs:V:c:C:i:j:u:t:d:R:P:w:W:m:M:F:T:O:L:I:"; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	while ((choice = getopt_long(argc, argv, iodine_args_short, iodine_args, NULL)) != -1) { | ||||||
| 		switch (choice) { | 		switch (choice) { | ||||||
| 		case '4': | 		case '4': | ||||||
| 			nameserv_family = AF_INET; | 			nameserv_family = AF_INET; | ||||||
| @@ -252,22 +246,22 @@ main(int argc, char **argv) | |||||||
| 			/* NOTREACHED */ | 			/* NOTREACHED */ | ||||||
| 			break; | 			break; | ||||||
| 		case 'V': | 		case 'V': | ||||||
| 			stats = atoi(optarg); | 			this.stats = atoi(optarg); | ||||||
| 			if (stats < 0) | 			if (this.stats < 0) | ||||||
| 				stats = 0; | 				this.stats = 0; | ||||||
| 			break; | 			break; | ||||||
| 		case 'f': | 		case 'f': | ||||||
| 			foreground = 1; | 			this.foreground = 1; | ||||||
| 			break; | 			break; | ||||||
| 		case 'D': | 		case 'D': | ||||||
| 			debug++; | 			this.debug++; | ||||||
| 			break; | 			break; | ||||||
| 		case 'h': | 		case 'h': | ||||||
| 			help(); | 			help(); | ||||||
| 			/* NOTREACHED */ | 			/* NOTREACHED */ | ||||||
| 			break; | 			break; | ||||||
| 		case 'r': | 		case 'r': | ||||||
| 			raw_mode = 0; | 			this.raw_mode = 0; | ||||||
| 			break; | 			break; | ||||||
| 		case 'u': | 		case 'u': | ||||||
| 			username = optarg; | 			username = optarg; | ||||||
| @@ -284,22 +278,22 @@ main(int argc, char **argv) | |||||||
| 			break; | 			break; | ||||||
| #endif | #endif | ||||||
| 		case 'P': | 		case 'P': | ||||||
| 			strncpy(password, optarg, sizeof(password)); | 			strncpy(this.password, optarg, sizeof(this.password)); | ||||||
| 			password[sizeof(password)-1] = 0; | 			this.password[sizeof(this.password)-1] = 0; | ||||||
|  |  | ||||||
| 			/* XXX: find better way of cleaning up ps(1) */ | 			/* XXX: find better way of cleaning up ps(1) */ | ||||||
| 			memset(optarg, 0, strlen(optarg)); | 			memset(optarg, 0, strlen(optarg)); | ||||||
| 			break; | 			break; | ||||||
| 		case 'm': | 		case 'm': | ||||||
| 			autodetect_frag_size = 0; | 			this.autodetect_frag_size = 0; | ||||||
| 			max_downstream_frag_size = atoi(optarg); | 			this.max_downstream_frag_size = atoi(optarg); | ||||||
| 			break; | 			break; | ||||||
| 		case 'M': | 		case 'M': | ||||||
| 			hostname_maxlen = atoi(optarg); | 			this.hostname_maxlen = atoi(optarg); | ||||||
| 			if (hostname_maxlen > 255) | 			if (this.hostname_maxlen > 255) | ||||||
| 				hostname_maxlen = 255; | 				this.hostname_maxlen = 255; | ||||||
| 			if (hostname_maxlen < 10) | 			if (this.hostname_maxlen < 10) | ||||||
| 				hostname_maxlen = 10; | 				this.hostname_maxlen = 10; | ||||||
| 			break; | 			break; | ||||||
| 		case 'z': | 		case 'z': | ||||||
| 			context = optarg; | 			context = optarg; | ||||||
| @@ -312,45 +306,48 @@ main(int argc, char **argv) | |||||||
| 				errx(5, "Invalid query type '%s'", optarg); | 				errx(5, "Invalid query type '%s'", optarg); | ||||||
| 			break; | 			break; | ||||||
| 		case 'O': | 		case 'O': | ||||||
| 			client_set_downenc(optarg); | 			if ((this.downenc = parse_encoding(optarg)) == 0) | ||||||
|  | 				errx(6, "Invalid encoding type '%s'", optarg); | ||||||
| 			break; | 			break; | ||||||
| 		case 'L': | 		case 'L': | ||||||
| 			lazymode = atoi(optarg); | 			this.lazymode = atoi(optarg); | ||||||
| 			if (lazymode > 1) | 			if (this.lazymode > 1) | ||||||
| 				lazymode = 1; | 				this.lazymode = 1; | ||||||
| 			if (lazymode < 0) | 			if (this.lazymode < 0) | ||||||
| 				lazymode = 0; | 				this.lazymode = 0; | ||||||
| 			break; | 			break; | ||||||
| 		case 'I': | 		case 'I': | ||||||
| 			target_interval_sec = strtod(optarg, NULL); | 			this.max_timeout_ms = strtod(optarg, NULL) * 1000; | ||||||
| 			break; | 			break; | ||||||
| 		case 'i': | 		case 'i': | ||||||
| 			server_timeout_sec = strtod(optarg, NULL); | 			this.server_timeout_ms = strtod(optarg, NULL) * 1000; | ||||||
| 			autodetect_server_timeout = 0; | 			this.autodetect_server_timeout = 0; | ||||||
| 			break; | 			break; | ||||||
| 		case 'j': | 		case 'j': | ||||||
| 			downstream_timeout_sec = strtod(optarg, NULL); | 			this.downstream_timeout_ms = strtod(optarg, NULL) * 1000; | ||||||
| 			if (autodetect_server_timeout) { | 			if (this.autodetect_server_timeout) { | ||||||
| 				autodetect_server_timeout = 0; | 				this.autodetect_server_timeout = 0; | ||||||
| 				server_timeout_sec = 4; | 				this.server_timeout_ms = 4000; | ||||||
| 			} | 			} | ||||||
| 			break; | 			break; | ||||||
| 		case 's': | 		case 's': | ||||||
| 			min_interval_ms = atoi(optarg); | 			this.send_interval_ms = atoi(optarg); | ||||||
| 			if (min_interval_ms < 0) | 			if (this.send_interval_ms < 0) | ||||||
| 				min_interval_ms = 0; | 				this.send_interval_ms = 0; | ||||||
| 		case 'w': | 		case 'w': | ||||||
| 			down_windowsize = atoi(optarg); | 			this.windowsize_down = atoi(optarg); | ||||||
| 			break; | 			break; | ||||||
| 		case 'W': | 		case 'W': | ||||||
| 			up_windowsize = atoi(optarg); | 			this.windowsize_up = atoi(optarg); | ||||||
| 			break; |  | ||||||
| 		case 'C': |  | ||||||
| 			up_compression = atoi(optarg) & 1; |  | ||||||
| 			break; | 			break; | ||||||
| 		case 'c': | 		case 'c': | ||||||
| 			down_compression = atoi(optarg) & 1; | 			this.compression_down = atoi(optarg) & 1; | ||||||
| 			break; | 			break; | ||||||
|  | 		case 'C': | ||||||
|  | 			this.compression_up = atoi(optarg) & 1; | ||||||
|  | 			break; | ||||||
|  | 		case 'X': | ||||||
|  | 			// TODO implement option for remote host/port to pipe stdin/out | ||||||
| 		default: | 		default: | ||||||
| 			usage(); | 			usage(); | ||||||
| 			/* NOTREACHED */ | 			/* NOTREACHED */ | ||||||
| @@ -362,120 +359,124 @@ main(int argc, char **argv) | |||||||
| 	argc -= optind; | 	argc -= optind; | ||||||
| 	argv += optind; | 	argv += optind; | ||||||
|  |  | ||||||
| 	if (debug) { | 	if (this.debug) { | ||||||
| 		fprintf(stderr, "Debug level %d enabled, will stay in foreground.\n", debug); | 		fprintf(stderr, "Debug level %d enabled, will stay in foreground.\n", this.debug); | ||||||
| 		fprintf(stderr, "Add more -D switches to set higher debug level.\n"); | 		fprintf(stderr, "Add more -D switches to set higher debug level.\n"); | ||||||
| 		foreground = 1; | 		this.foreground = 1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	nameserv_hosts_len = argc - 1; | 	this.nameserv_hosts_len = argc - 1; | ||||||
| 	if (nameserv_hosts_len <= 0) | 	if (this.nameserv_hosts_len <= 0) | ||||||
| 		nameserv_hosts_len = 1; | 		/* if no hosts specified, use resolv.conf */ | ||||||
|  | 		this.nameserv_hosts_len = 1; | ||||||
|  |  | ||||||
| 	// Preallocate memory with expected number of hosts | 	// Preallocate memory with expected number of hosts | ||||||
| 	nameserv_hosts = malloc(sizeof(char *) * nameserv_hosts_len); | 	this.nameserv_hosts = malloc(sizeof(char *) * this.nameserv_hosts_len); | ||||||
| 	nameserv_addrs = malloc(sizeof(struct sockaddr_storage) * nameserv_hosts_len); | 	this.nameserv_addrs = malloc(sizeof(struct sockaddr_storage) * this.nameserv_hosts_len); | ||||||
|  |  | ||||||
| 	if (argc == 0) { | 	if (argc == 0) { | ||||||
| 		usage(); | 		usage(); | ||||||
| 		/* NOT REACHED */ | 		/* NOT REACHED */ | ||||||
| 	} else if (argc == 1) { | 	} else if (argc == 1) { | ||||||
| 		nameserv_hosts[0] = get_resolvconf_addr(); | 		this.nameserv_hosts[0] = get_resolvconf_addr(); | ||||||
| 	} else if (argc > 1) | 	} else if (argc > 1) | ||||||
| 		for (int h = 0; h < nameserv_hosts_len; h++) nameserv_hosts[h] = strdup(argv[h + 1]); | 		for (int h = 0; h < this.nameserv_hosts_len; h++) | ||||||
| 	topdomain = strdup(argv[0]); | 			this.nameserv_hosts[h] = strdup(argv[h + 1]); | ||||||
|  | 	this.topdomain = strdup(argv[0]); | ||||||
|  |  | ||||||
| 	for (int n = 0; n < nameserv_hosts_len; n++) { | 	for (int n = 0; n < this.nameserv_hosts_len; n++) { | ||||||
| 		nameserv_host = nameserv_hosts[n]; | 		nameserv_host = this.nameserv_hosts[n]; | ||||||
| 		if (!nameserv_host) { | 		if (!nameserv_host) { | ||||||
| 			errx(1, "Error processing nameserver hostnames!\n"); | 			errx(1, "Error processing nameserver hostnames!"); | ||||||
| 		} | 		} | ||||||
| 		nameservaddr_len = get_addr(nameserv_host, DNS_PORT, nameserv_family, 0, &nameservaddr); | 		nameservaddr_len = get_addr(nameserv_host, DNS_PORT, nameserv_family, 0, &nameservaddr); | ||||||
| 		if (nameservaddr_len < 0) { | 		if (nameservaddr_len < 0) { | ||||||
| 			errx(1, "Cannot lookup nameserver '%s': %s ", | 			errx(1, "Cannot lookup nameserver '%s': %s ", | ||||||
| 					nameserv_host, gai_strerror(nameservaddr_len)); | 					nameserv_host, gai_strerror(nameservaddr_len)); | ||||||
| 		} | 		} | ||||||
| 		memcpy(&nameserv_addrs[n], &nameservaddr, sizeof(struct sockaddr_storage)); | 		memcpy(&this.nameserv_addrs[n], &nameservaddr, sizeof(struct sockaddr_storage)); | ||||||
| 		nameserv_addrs_len ++; | 		this.nameserv_addrs_len ++; | ||||||
| 		nameserv_host = NULL; | 		nameserv_host = NULL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (nameserv_addrs_len <= 0 || !nameserv_hosts[0]) { | 	if (this.nameserv_addrs_len <= 0 || !this.nameserv_hosts[0]) { | ||||||
| 		warnx("No nameserver found - not connected to any network?\n"); | 		warnx("No nameservers found - not connected to any network?"); | ||||||
| 		usage(); | 		usage(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	client_set_nameservers(nameserv_addrs, nameserv_addrs_len); | 	// TODO remove client_set_... functions | ||||||
|  | //	client_set_nameservers(nameserv_addrs, nameserv_addrs_len); | ||||||
|  |  | ||||||
| 	if (max_downstream_frag_size < 1 || max_downstream_frag_size > 0xffff) { | 	if (this.max_downstream_frag_size < 10 || this.max_downstream_frag_size > MAX_FRAGSIZE) { | ||||||
| 		warnx("Use a max frag size between 1 and 65535 bytes.\n"); | 		warnx("Use a max frag size between 10 and %d bytes.", MAX_FRAGSIZE); | ||||||
| 		usage(); | 		usage(); | ||||||
| 		/* NOTREACHED */ | 		/* NOTREACHED */ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if(check_topdomain(topdomain, &errormsg)) { | 	if(check_topdomain(this.topdomain, &errormsg)) { | ||||||
| 		warnx("Invalid topdomain: %s", errormsg); | 		warnx("Invalid topdomain: %s", errormsg); | ||||||
| 		usage(); | 		usage(); | ||||||
| 		/* NOTREACHED */ | 		/* NOTREACHED */ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (up_windowsize < 1 || down_windowsize < 1) { | 	int max_ws = MAX_SEQ_ID / 2; | ||||||
| 		warnx("Windowsize (-w or -W) must be greater than 0!"); | 	if (this.windowsize_up < 1 || this.windowsize_down < 1 || | ||||||
|  | 		this.windowsize_up > max_ws || this.windowsize_down > max_ws) { | ||||||
|  | 		warnx("Window sizes (-w or -W) must be between 0 and %d!", max_ws); | ||||||
| 		usage(); | 		usage(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (target_interval_sec < 0.1) { | 	if (this.max_timeout_ms < 100) { | ||||||
| 		warnx("Target interval must be greater than 0.1 seconds!"); | 		warnx("Target interval (-I) must be greater than 0.1 seconds!"); | ||||||
| 		usage(); | 		usage(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (server_timeout_sec < 0.1 || server_timeout_sec >= target_interval_sec) { | 	if (this.server_timeout_ms < 100 || this.server_timeout_ms >= this.max_timeout_ms) { | ||||||
| 		warnx("Server timeout must be greater than 0.1 sec and less than target interval!"); | 		warnx("Server timeout (-i) must be greater than 0.1 sec and less than target interval!"); | ||||||
| 		usage(); | 		usage(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (downstream_timeout_sec < 0.1) { | 	if (this.downstream_timeout_ms < 100) { | ||||||
| 		warnx("Downstream fragment timeout must be more than 0.1 sec to prevent excessive retransmits."); | 		warnx("Downstream fragment timeout must be more than 0.1 sec to prevent excessive retransmits."); | ||||||
| 		usage(); | 		usage(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (!lazymode && target_interval_sec > 1) { | 	if (!this.lazymode && this.max_timeout_ms > 1000) { | ||||||
| 		warnx("Warning: Target interval of >1 second in immediate mode will cause high latency."); | 		fprintf(stderr, "Warning: Target interval of >1 second in immediate mode will cause high latency.\n"); | ||||||
| 		usage(); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	client_set_compression(up_compression, down_compression); | //	client_set_compression(up_compression, down_compression); | ||||||
| 	client_set_dnstimeout(target_interval_sec, server_timeout_sec, downstream_timeout_sec, autodetect_server_timeout); | //	client_set_dnstimeout(target_interval_sec, server_timeout_sec, downstream_timeout_sec, autodetect_server_timeout); | ||||||
| 	client_set_interval(target_interval_sec * 1000.0, min_interval_ms); | //	client_set_interval(target_interval_sec * 1000.0, min_interval_ms); | ||||||
| 	client_set_lazymode(lazymode); | //	client_set_lazymode(lazymode); | ||||||
| 	client_set_topdomain(topdomain); | //	client_set_topdomain(topdomain); | ||||||
| 	client_set_hostname_maxlen(hostname_maxlen); | //	client_set_hostname_maxlen(hostname_maxlen); | ||||||
| 	client_set_windowsize(up_windowsize, down_windowsize); | //	client_set_windowsize(up_windowsize, down_windowsize); | ||||||
|  |  | ||||||
| 	if (username != NULL) { | 	if (username != NULL) { | ||||||
| #ifndef WINDOWS32 | #ifndef WINDOWS32 | ||||||
| 		if ((pw = getpwnam(username)) == NULL) { | 		if ((pw = getpwnam(username)) == NULL) { | ||||||
| 			warnx("User %s does not exist!\n", username); | 			warnx("User %s does not exist!", username); | ||||||
| 			usage(); | 			usage(); | ||||||
| 			/* NOTREACHED */ | 			/* NOTREACHED */ | ||||||
| 		} | 		} | ||||||
|  | #else | ||||||
|  | 		warnx("Warning: Cannot switch user on Windows systems."); | ||||||
| #endif | #endif | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (strlen(password) == 0) { | 	if (strlen(this.password) == 0) { | ||||||
| 		if (NULL != getenv(PASSWORD_ENV_VAR)) | 		if (NULL != getenv(PASSWORD_ENV_VAR)) | ||||||
| 			snprintf(password, sizeof(password), "%s", getenv(PASSWORD_ENV_VAR)); | 			snprintf(this.password, sizeof(this.password), "%s", getenv(PASSWORD_ENV_VAR)); | ||||||
| 		else | 		else | ||||||
| 			read_password(password, sizeof(password)); | 			read_password(this.password, sizeof(this.password)); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	client_set_password(password); | 	if ((this.tun_fd = open_tun(device)) == -1) { | ||||||
|  |  | ||||||
| 	if ((tun_fd = open_tun(device)) == -1) { |  | ||||||
| 		retval = 1; | 		retval = 1; | ||||||
| 		goto cleanup1; | 		goto cleanup1; | ||||||
| 	} | 	} | ||||||
| 	if ((dns_fd = open_dns_from_host(NULL, 0, nameservaddr.ss_family, AI_PASSIVE)) < 0) { | 	if ((this.dns_fd = open_dns_from_host(NULL, 0, nameservaddr.ss_family, AI_PASSIVE)) < 0) { | ||||||
| 		retval = 1; | 		retval = 1; | ||||||
| 		goto cleanup2; | 		goto cleanup2; | ||||||
| 	} | 	} | ||||||
| @@ -487,24 +488,25 @@ main(int argc, char **argv) | |||||||
| 	signal(SIGINT, sighandler); | 	signal(SIGINT, sighandler); | ||||||
| 	signal(SIGTERM, sighandler); | 	signal(SIGTERM, sighandler); | ||||||
|  |  | ||||||
| 	fprintf(stderr, "Sending DNS queries for %s to ", topdomain); | 	fprintf(stderr, "Sending DNS queries for %s to ", this.topdomain); | ||||||
| 	for (int a = 0; a < nameserv_addrs_len; a++) | 	for (int a = 0; a < this.nameserv_addrs_len; a++) | ||||||
| 		fprintf(stderr, "%s%s", format_addr(&nameserv_addrs[a], nameservaddr_len), | 		fprintf(stderr, "%s%s", format_addr(&this.nameserv_addrs[a], sizeof(struct sockaddr_storage)), | ||||||
| 				(a != nameserv_addrs_len-1) ?  ", " : ""); | 				(a != this.nameserv_addrs_len - 1) ?  ", " : ""); | ||||||
| 	fprintf(stderr, "\n"); | 	fprintf(stderr, "\n"); | ||||||
|  |  | ||||||
| 	if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) { | 	// TODO not pass args to client stuff - use "this" as shared instance | ||||||
|  | 	if (client_handshake(this.dns_fd, this.raw_mode, this.autodetect_frag_size, this.max_downstream_frag_size)) { | ||||||
| 		retval = 1; | 		retval = 1; | ||||||
| 		goto cleanup2; | 		goto cleanup2; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (client_get_conn() == CONN_RAW_UDP) { | 	if (this.conn == CONN_RAW_UDP) { | ||||||
| 		fprintf(stderr, "Sending raw traffic directly to %s\n", client_get_raw_addr()); | 		fprintf(stderr, "Sending raw UDP traffic directly to %s\n", client_get_raw_addr()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	fprintf(stderr, "Connection setup complete, transmitting data.\n"); | 	fprintf(stderr, "Connection setup complete, transmitting data.\n"); | ||||||
|  |  | ||||||
| 	if (foreground == 0) | 	if (this.foreground == 0) | ||||||
| 		do_detach(); | 		do_detach(); | ||||||
|  |  | ||||||
| 	if (pidfile != NULL) | 	if (pidfile != NULL) | ||||||
| @@ -528,11 +530,12 @@ main(int argc, char **argv) | |||||||
| 	if (context != NULL) | 	if (context != NULL) | ||||||
| 		do_setcon(context); | 		do_setcon(context); | ||||||
|  |  | ||||||
| 	client_tunnel(tun_fd, dns_fd); | 	// todo don't pass args again. | ||||||
|  | 	client_tunnel(this.tun_fd, this.dns_fd); | ||||||
|  |  | ||||||
| cleanup2: | cleanup2: | ||||||
| 	close_dns(dns_fd); | 	close_dns(this.dns_fd); | ||||||
| 	close_tun(tun_fd); | 	close_tun(this.tun_fd); | ||||||
| cleanup1: | cleanup1: | ||||||
|  |  | ||||||
| 	return retval; | 	return retval; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 frekky
					frekky