From 506c1de67eb342cbae0ecde6eedc2c590079a3a6 Mon Sep 17 00:00:00 2001 From: frekky Date: Sat, 9 Jan 2016 15:03:37 +0800 Subject: [PATCH] Refactor server code to use global server_instance --- src/iodined.c | 223 ++++++++++++++++++++++++-------------------------- src/server.c | 202 ++++++++++++++++++--------------------------- src/server.h | 63 ++++++++------ src/user.c | 4 +- 4 files changed, 226 insertions(+), 266 deletions(-) diff --git a/src/iodined.c b/src/iodined.c index 1bac743..14e8b69 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -72,8 +72,40 @@ #ifdef WINDOWS32 WORD req_version = MAKEWORD(2, 2); WSADATA wsa_data; + +#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 +static void +syslog(int a, const char *str, ...) +{ + /* TODO: implement (add to event log), move to common.c */ + ; +} #endif +/* Definition of main server instance */ +struct server_instance server; + +static struct server_instance preset_default = { + .check_ip = 1, + .netmask = 27, + .ns_ip = INADDR_ANY, + .mtu = 1130, /* Very many relays give fragsize 1150 or slightly + higher for NULL; tun/zlib adds ~17 bytes. */ + .port = 53, + .addrfamily = AF_UNSPEC, + + /* Mark both file descriptors as unused */ + .dns_fds.v4fd = -1, + .dns_fds.v6fd = -1 +}; + /* Ask ipify.org webservice to get external ip */ static int get_external_ip(struct in_addr *ip) @@ -130,26 +162,9 @@ get_external_ip(struct in_addr *ip) static void sigint(int sig) { - server_stop(); + server.running = 0; } -#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 -static void -syslog(int a, const char *str, ...) -{ - /* TODO: implement (add to event log), move to common.c */ - ; -} -#endif - static void print_usage() { extern char *__progname; @@ -235,7 +250,7 @@ main(int argc, char **argv) char *listen_ip6; char *errormsg; #ifndef WINDOWS32 - struct passwd *pw; + struct passwd *pw = NULL; #endif int foreground; char *username; @@ -243,59 +258,35 @@ main(int argc, char **argv) char *context; char *device; char *pidfile; - int addrfamily; - struct dnsfd dns_fds; - int tun_fd; - - /* settings for forwarding normal DNS to - * local real DNS server */ - int bind_fd; - int bind_enable; int choice; - int port; - int mtu; + int skipipconfig; char *netsize; int ns_get_externalip; int retval; - int max_idle_time = 0; - struct sockaddr_storage dns4addr; - int dns4addr_len; - struct sockaddr_storage dns6addr; - int dns6addr_len; + #ifdef HAVE_SYSTEMD int nb_fds; #endif -#ifndef WINDOWS32 - pw = NULL; -#endif errormsg = NULL; username = NULL; newroot = NULL; context = NULL; device = NULL; foreground = 0; - bind_enable = 0; - bind_fd = 0; - mtu = 1130; /* Very many relays give fragsize 1150 or slightly - higher for NULL; tun/zlib adds ~17 bytes. */ - dns4addr_len = 0; - dns6addr_len = 0; listen_ip4 = NULL; listen_ip6 = NULL; - port = 53; + + ns_get_externalip = 0; - addrfamily = AF_UNSPEC; skipipconfig = 0; pidfile = NULL; srand(time(NULL)); retval = 0; - server_init(); - #ifdef WINDOWS32 WSAStartup(req_version, &wsa_data); #endif @@ -311,16 +302,16 @@ main(int argc, char **argv) while ((choice = getopt(argc, argv, "46vcsfhDu:t:d:m:l:L:p:n:b:P:z:F:i:")) != -1) { switch(choice) { case '4': - addrfamily = AF_INET; + server.addrfamily = AF_INET; break; case '6': - addrfamily = AF_INET6; + server.addrfamily = AF_INET6; break; case 'v': version(); break; case 'c': - check_ip = 0; + server.check_ip = 0; break; case 's': skipipconfig = 1; @@ -332,7 +323,7 @@ main(int argc, char **argv) help(); break; case 'D': - debug++; + server.debug++; break; case 'u': username = optarg; @@ -344,7 +335,7 @@ main(int argc, char **argv) device = optarg; break; case 'm': - mtu = atoi(optarg); + server.mtu = atoi(optarg); break; case 'l': listen_ip4 = optarg; @@ -353,28 +344,28 @@ main(int argc, char **argv) listen_ip6 = optarg; break; case 'p': - port = atoi(optarg); + server.port = atoi(optarg); break; case 'n': if (optarg && strcmp("auto", optarg) == 0) { ns_get_externalip = 1; } else { - ns_ip = inet_addr(optarg); + server.ns_ip = inet_addr(optarg); } break; case 'b': - bind_enable = 1; - bind_port = atoi(optarg); + server.bind_enable = 1; + server.bind_port = atoi(optarg); break; case 'F': pidfile = optarg; break; case 'i': - max_idle_time = atoi(optarg); + server.max_idle_time = atoi(optarg); break; case 'P': - strncpy(password, optarg, sizeof(password)); - password[sizeof(password)-1] = 0; + 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)); @@ -400,18 +391,18 @@ main(int argc, char **argv) if (netsize) { *netsize = 0; netsize++; - netmask = atoi(netsize); + server.netmask = atoi(netsize); } - my_ip = inet_addr(argv[0]); + server.my_ip = inet_addr(argv[0]); - if (my_ip == INADDR_NONE) { + if (server.my_ip == INADDR_NONE) { warnx("Bad IP address to use inside tunnel."); usage(); } - topdomain = strdup(argv[1]); - if(check_topdomain(topdomain, &errormsg)) { + server.topdomain = strdup(argv[1]); + if(check_topdomain(server.topdomain, &errormsg)) { warnx("Invalid topdomain: %s", errormsg); usage(); /* NOTREACHED */ @@ -426,57 +417,59 @@ main(int argc, char **argv) #endif } - if (mtu <= 0) { + if (server.mtu <= 0) { warnx("Bad MTU given."); usage(); } - if(port < 1 || port > 65535) { + if(server.port < 1 || server.port > 65535) { warnx("Bad port number given."); usage(); } - if (port != 53) { + 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", port); + fprintf(stderr, "You must manually forward port 53 to port %d for things to work.\n", server.port); } - if (debug) { - fprintf(stderr, "Debug level %d enabled, will stay in foreground.\n", debug); + 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 (addrfamily == AF_UNSPEC || addrfamily == AF_INET) { - dns4addr_len = get_addr(listen_ip4, port, AF_INET, AI_PASSIVE | AI_NUMERICHOST, &dns4addr); - if (dns4addr_len < 0) { + 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 (addrfamily == AF_UNSPEC || addrfamily == AF_INET6) { - dns6addr_len = get_addr(listen_ip6, port, AF_INET6, AI_PASSIVE | AI_NUMERICHOST, &dns6addr); - if (dns6addr_len < 0) { + 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(bind_enable) { - in_addr_t dns_ip = ((struct sockaddr_in *) &dns4addr)->sin_addr.s_addr; - if (bind_port < 1 || bind_port > 65535) { + 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 (bind_port == port && (dns_ip == INADDR_ANY || dns_ip == htonl(0x7f000001L))) { - warnx("Forward port is same as listen port (%d), will create a loop!", bind_port); + if (server.bind_port == server.port && (dns_ip == INADDR_ANY || dns_ip == htonl(0x7f000001L))) { + 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", - topdomain, bind_port); + server.topdomain, server.bind_port); } if (ns_get_externalip) { @@ -486,39 +479,35 @@ main(int argc, char **argv) fprintf(stderr, "Failed to get external IP via web service.\n"); exit(3); } - ns_ip = extip.s_addr; + server.ns_ip = extip.s_addr; fprintf(stderr, "Using %s as external IP.\n", inet_ntoa(extip)); } - if (ns_ip == INADDR_NONE) { + if (server.ns_ip == INADDR_NONE) { warnx("Bad IP address to return as nameserver."); usage(); } - if (netmask > 30 || netmask < 8) { - warnx("Bad netmask (%d bits). Use 8-30 bits.", netmask); + if (server.netmask > 30 || server.netmask < 8) { + warnx("Bad netmask (%d bits). Use 8-30 bits.", server.netmask); usage(); } - if (strlen(password) == 0) { + if (strlen(server.password) == 0) { if (NULL != getenv(PASSWORD_ENV_VAR)) - snprintf(password, sizeof(password), "%s", getenv(PASSWORD_ENV_VAR)); + snprintf(server.password, sizeof(server.password), "%s", getenv(PASSWORD_ENV_VAR)); else - read_password(password, sizeof(password)); + read_password(server.password, sizeof(server.password)); } - /* Mark both file descriptors as unused */ - dns_fds.v4fd = -1; - dns_fds.v6fd = -1; + created_users = init_users(server.my_ip, server.netmask); - created_users = init_users(my_ip, netmask); - - if ((tun_fd = open_tun(device)) == -1) { + 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, netmask) != 0 || tun_setmtu(mtu) != 0) { + if (tun_setip(argv[0], other_ip, server.netmask) != 0 || tun_setmtu(server.mtu) != 0) { retval = 1; free((void*) other_ip); goto cleanup; @@ -537,15 +526,15 @@ main(int argc, char **argv) dns_fds.v4fd = SD_LISTEN_FDS_START; } else { #endif - if ((addrfamily == AF_UNSPEC || addrfamily == AF_INET) && - (dns_fds.v4fd = open_dns(&dns4addr, dns4addr_len)) < 0) { + 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 ((addrfamily == AF_UNSPEC || addrfamily == AF_INET6) && + if ((server.addrfamily == AF_UNSPEC || server.addrfamily == AF_INET6) && /* Set IPv6 socket to V6ONLY */ - (dns_fds.v6fd = open_dns_opt(&dns6addr, dns6addr_len, 1)) < 0) { + (server.dns_fds.v6fd = open_dns_opt(&server.dns6addr, server.dns6addr_len, 1)) < 0) { retval = 1; goto cleanup; @@ -555,25 +544,23 @@ main(int argc, char **argv) #endif /* 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); + 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 (bind_enable) { - if ((bind_fd = open_dns_from_host(NULL, 0, AF_INET, 0)) < 0) { + if (server.bind_enable) { + if ((server.bind_fd = open_dns_from_host(NULL, 0, AF_INET, 0)) < 0) { retval = 1; goto cleanup; } } - my_mtu = mtu; - if (created_users < USERS) { fprintf(stderr, "Limiting to %d simultaneous users because of netmask /%d\n", - created_users, netmask); + created_users, server.netmask); } - fprintf(stderr, "Listening to dns for domain %s\n", topdomain); + fprintf(stderr, "Listening to dns for domain %s\n", server.topdomain); if (foreground == 0) do_detach(); @@ -606,18 +593,18 @@ main(int argc, char **argv) if (context != NULL) do_setcon(context); - syslog(LOG_INFO, "started, listening on port %d", port); + syslog(LOG_INFO, "started, listening on port %d", server.port); - server_tunnel(tun_fd, &dns_fds, bind_fd, max_idle_time); + server_tunnel(); syslog(LOG_INFO, "stopping"); - close_dns(bind_fd); + close_dns(server.bind_fd); cleanup: - if (dns_fds.v6fd >= 0) - close_dns(dns_fds.v6fd); - if (dns_fds.v4fd >= 0) - close_dns(dns_fds.v4fd); - close_tun(tun_fd); + if (server.dns_fds.v6fd >= 0) + close_dns(server.dns_fds.v6fd); + if (server.dns_fds.v4fd >= 0) + close_dns(server.dns_fds.v4fd); + close_tun(server.tun_fd); return retval; } diff --git a/src/server.c b/src/server.c index c5f840d..0e37af9 100644 --- a/src/server.c +++ b/src/server.c @@ -58,47 +58,6 @@ WSADATA wsa_data; #include #endif -/* Global server variables */ -int running = 1; -char *topdomain; -char password[33]; -struct encoder *b32; -struct encoder *b64; -struct encoder *b64u; -struct encoder *b128; - -int check_ip; -int my_mtu; -in_addr_t my_ip; -int netmask; - -in_addr_t ns_ip; - -int bind_port; -int debug; - -void -server_init() -{ - running = 1; - ns_ip = INADDR_ANY; - netmask = 27; - debug = 0; - check_ip = 1; - memset(password, 0, sizeof(password)); - fw_query_init(); - b32 = get_base32_encoder(); - b64 = get_base64_encoder(); - b64u = get_base64u_encoder(); - b128 = get_base128_encoder(); -} - -void -server_stop() -{ - running = 0; -} - static void send_raw(int fd, uint8_t *buf, size_t buflen, int user, int cmd, struct sockaddr_storage *from, socklen_t fromlen) { @@ -143,7 +102,7 @@ send_raw(int fd, uint8_t *buf, size_t buflen, int user, int cmd, struct sockaddr during a session (given QMEM_LEN is not very large). */ #define QMEM_DEBUG(l, u, ...) \ - if (debug >= l) {\ + if (server.debug >= l) {\ TIMEPRINT("[QMEM u%d (%lu/%u)] ", u, users[u].qmem.num_pending, users[u].outgoing->windowsize); \ fprintf(stderr, __VA_ARGS__);\ fprintf(stderr, "\n");\ @@ -284,7 +243,7 @@ qmem_get_next_response(int userid) } static struct timeval -qmem_max_wait(struct dnsfd *dns_fds, int *touser, struct query **sendq) +qmem_max_wait(int *touser, struct query **sendq) /* Gets max interval before the next query has to be responded to * Response(s) are sent automatically for queries if: * - the query has timed out @@ -358,7 +317,7 @@ qmem_max_wait(struct dnsfd *dns_fds, int *touser, struct query **sendq) QMEM_DEBUG(4, userid, "ANSWER q id %d, ACK %d; sent %lu of %lu + sending another %lu", q->id, u->next_upstream_ack, sent, total, sending); - send_data_or_ping(dns_fds, userid, q, 0, immediate); + send_data_or_ping(userid, q, 0, immediate); if (sending > 0) sending--; @@ -377,7 +336,7 @@ qmem_max_wait(struct dnsfd *dns_fds, int *touser, struct query **sendq) } } - if (debug >= 5) { + if (server.debug >= 5) { time_t soonest_ms = timeval_to_ms(&soonest); if (nextq && nextuser >= 0) { QMEM_DEBUG(5, nextuser, "can wait for %lu ms, will send id %d", soonest_ms, nextq->id); @@ -435,7 +394,7 @@ forward_query(int bind_fd, struct query *q) newaddr = inet_addr("127.0.0.1"); myaddr = (struct sockaddr_in *) &(q->from); memcpy(&(myaddr->sin_addr), &newaddr, sizeof(in_addr_t)); - myaddr->sin_port = htons(bind_port); + myaddr->sin_port = htons(server.bind_port); DEBUG(2, "TX: NS reply"); @@ -471,8 +430,7 @@ send_version_response(int fd, version_ack_t ack, uint32_t payload, int userid, s } void -send_data_or_ping(struct dnsfd *dns_fds, int userid, struct query *q, - int ping, int immediate) +send_data_or_ping(int userid, struct query *q, int ping, int immediate) /* Sends current fragment to user, or a ping if no data available. ping: 1=force send ping (even if data available), 0=only send if no data. immediate: 1=not from qmem (ie. fresh query), 0=query is from qmem */ @@ -527,7 +485,7 @@ send_data_or_ping(struct dnsfd *dns_fds, int userid, struct query *q, if (f) memcpy(pkt + headerlen, f->data, datalen); - write_dns(get_dns_fd(dns_fds, &q->from), q, (char *)pkt, + write_dns(get_dns_fd(&server.dns_fds, &q->from), q, (char *)pkt, datalen + headerlen, users[userid].downenc); /* mark query as answered */ @@ -536,7 +494,7 @@ send_data_or_ping(struct dnsfd *dns_fds, int userid, struct query *q, } void -user_process_incoming_data(int tun_fd, struct dnsfd *dns_fds, int userid, int ack) +user_process_incoming_data(int userid, int ack) { uint8_t pkt[65536]; size_t datalen; @@ -553,13 +511,12 @@ user_process_incoming_data(int tun_fd, struct dnsfd *dns_fds, int userid, int ac if (datalen > 0) { /* Data reassembled successfully + cleared out of buffer */ - handle_full_packet(tun_fd, dns_fds, userid, pkt, datalen, compressed); + handle_full_packet(userid, pkt, datalen, compressed); } } static int -user_send_data(int userid, struct dnsfd *dns_fds, uint8_t *indata, - size_t len, int compressed) +user_send_data(int userid, uint8_t *indata, size_t len, int compressed) /* Appends data to a user's outgoing queue and sends it (in raw mode only) */ { size_t datalen; @@ -592,7 +549,7 @@ user_send_data(int userid, struct dnsfd *dns_fds, uint8_t *indata, } else if (data && datalen) { /* CONN_RAW_UDP */ if (!compressed) DEBUG(1, "Sending in RAW mode uncompressed to user %d!", userid); - int dns_fd = get_dns_fd(dns_fds, &users[userid].host); + int dns_fd = get_dns_fd(&server.dns_fds, &users[userid].host); send_raw(dns_fd, data, datalen, userid, RAW_HDR_CMD_DATA, &users[userid].host, users[userid].hostlen); ret = 1; @@ -602,7 +559,7 @@ user_send_data(int userid, struct dnsfd *dns_fds, uint8_t *indata, } static int -tunnel_bind(int bind_fd, struct dnsfd *dns_fds) +tunnel_bind() { char packet[64*1024]; struct sockaddr_storage from; @@ -613,7 +570,7 @@ tunnel_bind(int bind_fd, struct dnsfd *dns_fds) int r; fromlen = sizeof(struct sockaddr); - r = recvfrom(bind_fd, packet, sizeof(packet), 0, + r = recvfrom(server.bind_fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &fromlen); if (r <= 0) @@ -633,7 +590,7 @@ tunnel_bind(int bind_fd, struct dnsfd *dns_fds) DEBUG(3, "TX: client %s id %u, %d bytes", format_addr(&query->addr, query->addrlen), (id & 0xffff), r); - dns_fd = get_dns_fd(dns_fds, &query->addr); + dns_fd = get_dns_fd(&server.dns_fds, &query->addr); if (sendto(dns_fd, packet, r, 0, (const struct sockaddr *) &(query->addr), query->addrlen) <= 0) { warn("forward reply error"); @@ -643,14 +600,14 @@ tunnel_bind(int bind_fd, struct dnsfd *dns_fds) } static int -tunnel_tun(int tun_fd, struct dnsfd *dns_fds) +tunnel_tun() { struct ip *header; static uint8_t in[64*1024]; int userid; int read; - if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0) + if ((read = read_tun(server.tun_fd, in, sizeof(in))) <= 0) return 0; /* find target ip in packet, in is padded with 4 bytes TUN header */ @@ -662,25 +619,25 @@ tunnel_tun(int tun_fd, struct dnsfd *dns_fds) DEBUG(3, "IN: %d byte pkt from tun to user %d; compression %d", read, userid, users[userid].down_compression); - return user_send_data(userid, dns_fds, in, read, 0); + return user_send_data(userid, in, read, 0); } static int -tunnel_dns(int tun_fd, int dns_fd, struct dnsfd *dns_fds, int bind_fd) +tunnel_dns(int dns_fd) { struct query q; int read; int domain_len; int inside_topdomain = 0; - if ((read = read_dns(dns_fd, dns_fds, tun_fd, &q)) <= 0) + if ((read = read_dns(dns_fd, &q)) <= 0) return 0; DEBUG(3, "RX: client %s ID %5d, type %d, name %s", format_addr(&q.from, q.fromlen), q.id, q.type, q.name); - domain_len = strlen(q.name) - strlen(topdomain); - if (domain_len >= 0 && !strcasecmp(q.name + domain_len, topdomain)) + domain_len = strlen(q.name) - strlen(server.topdomain); + if (domain_len >= 0 && !strcasecmp(q.name + domain_len, server.topdomain)) inside_topdomain = 1; /* require dot before topdomain */ if (domain_len >= 1 && q.name[domain_len - 1] != '.') @@ -719,7 +676,7 @@ tunnel_dns(int tun_fd, int dns_fd, struct dnsfd *dns_fds, int bind_fd) case T_SRV: case T_TXT: /* encoding is "transparent" here */ - handle_null_request(tun_fd, dns_fd, dns_fds, &q, domain_len); + handle_null_request(dns_fd, &q, domain_len); break; case T_NS: handle_ns_request(dns_fd, &q); @@ -730,15 +687,15 @@ tunnel_dns(int tun_fd, int dns_fd, struct dnsfd *dns_fds, int bind_fd) } else { /* Forward query to other port ? */ DEBUG(2, "Requested domain outside our topdomain."); - if (bind_fd) { - forward_query(bind_fd, &q); + if (server.bind_fd) { + forward_query(server.bind_fd, &q); } } return 0; } int -server_tunnel(int tun_fd, struct dnsfd *dns_fds, int bind_fd, int max_idle_time) +server_tunnel() { struct timeval tv; fd_set fds; @@ -747,72 +704,72 @@ server_tunnel(int tun_fd, struct dnsfd *dns_fds, int bind_fd, int max_idle_time) struct query *answer_now = NULL; time_t last_action = time(NULL); - if (debug >= 5) - window_debug = debug - 3; + if (server.debug >= 5) + window_debug = server.debug - 3; - while (running) { + while (server.running) { int maxfd; /* max wait time based on pending queries */ - tv = qmem_max_wait(dns_fds, &userid, &answer_now); + tv = qmem_max_wait(&userid, &answer_now); FD_ZERO(&fds); maxfd = 0; - if (dns_fds->v4fd >= 0) { - FD_SET(dns_fds->v4fd, &fds); - maxfd = MAX(dns_fds->v4fd, maxfd); + if (server.dns_fds.v4fd >= 0) { + FD_SET(server.dns_fds.v4fd, &fds); + maxfd = MAX(server.dns_fds.v4fd, maxfd); } - if (dns_fds->v6fd >= 0) { - FD_SET(dns_fds->v6fd, &fds); - maxfd = MAX(dns_fds->v6fd, maxfd); + if (server.dns_fds.v6fd >= 0) { + FD_SET(server.dns_fds.v6fd, &fds); + maxfd = MAX(server.dns_fds.v6fd, maxfd); } - if (bind_fd) { + if (server.bind_fd) { /* wait for replies from real DNS */ - FD_SET(bind_fd, &fds); - maxfd = MAX(bind_fd, maxfd); + FD_SET(server.bind_fd, &fds); + maxfd = MAX(server.bind_fd, maxfd); } /* Don't read from tun if all users have filled outpacket queues */ if(!all_users_waiting_to_send()) { - FD_SET(tun_fd, &fds); - maxfd = MAX(tun_fd, maxfd); + FD_SET(server.tun_fd, &fds); + maxfd = MAX(server.tun_fd, maxfd); } i = select(maxfd + 1, &fds, NULL, NULL, &tv); if(i < 0) { - if (running) + if (server.running) warn("select"); return 1; } if (i == 0) { - if (max_idle_time) { + if (server.max_idle_time) { /* only trigger the check if that's worth ( ie, no need to loop over if there is something to send */ - if (difftime(time(NULL), last_action) > max_idle_time) { + if (difftime(time(NULL), last_action) > server.max_idle_time) { for (userid = 0; userid < created_users; userid++) { last_action = (users[userid].last_pkt > last_action) ? users[userid].last_pkt : last_action; } - if (difftime(time(NULL), last_action) > max_idle_time) { + if (difftime(time(NULL), last_action) > server.max_idle_time) { fprintf(stderr, "Server idle for too long, shutting down...\n"); - running = 0; + server.running = 0; } } } } else { - if (FD_ISSET(tun_fd, &fds)) { - tunnel_tun(tun_fd, dns_fds); + if (FD_ISSET(server.tun_fd, &fds)) { + tunnel_tun(); } - if (FD_ISSET(dns_fds->v4fd, &fds)) { - tunnel_dns(tun_fd, dns_fds->v4fd, dns_fds, bind_fd); + if (FD_ISSET(server.dns_fds.v4fd, &fds)) { + tunnel_dns(server.dns_fds.v4fd); } - if (FD_ISSET(dns_fds->v6fd, &fds)) { - tunnel_dns(tun_fd, dns_fds->v6fd, dns_fds, bind_fd); + if (FD_ISSET(server.dns_fds.v6fd, &fds)) { + tunnel_dns(server.dns_fds.v6fd); } - if (FD_ISSET(bind_fd, &fds)) { - tunnel_bind(bind_fd, dns_fds); + if (FD_ISSET(server.bind_fd, &fds)) { + tunnel_bind(); } } } @@ -821,7 +778,7 @@ server_tunnel(int tun_fd, struct dnsfd *dns_fds, int bind_fd, int max_idle_time) } void -handle_full_packet(int tun_fd, struct dnsfd *dns_fds, int userid, uint8_t *data, size_t len, int compressed) +handle_full_packet(int userid, uint8_t *data, size_t len, int compressed) { size_t rawlen; uint8_t out[64*1024], *rawdata; @@ -846,13 +803,13 @@ handle_full_packet(int tun_fd, struct dnsfd *dns_fds, int userid, uint8_t *data, DEBUG(2, "FULL PKT: %lu bytes from user %d (touser %d)", len, userid, touser); if (touser == -1) { /* send the uncompressed packet to tun device */ - write_tun(tun_fd, rawdata, rawlen); + write_tun(server.tun_fd, rawdata, rawlen); } else { /* don't re-compress if possible */ if (users[touser].down_compression && compressed) { - user_send_data(touser, dns_fds, data, len, 1); + user_send_data(touser, data, len, 1); } else { - user_send_data(touser, dns_fds, rawdata, rawlen, 0); + user_send_data(touser, rawdata, rawlen, 0); } } } else { @@ -879,7 +836,7 @@ handle_raw_login(uint8_t *packet, size_t len, struct query *q, int fd, int useri DEBUG(1, "RX-raw: login, len %lu, from user %d", len, userid); /* User sends hash of seed + 1 */ - login_calculate(myhash, 16, password, users[userid].seed + 1); + login_calculate(myhash, 16, server.password, users[userid].seed + 1); if (memcmp(packet, myhash, 16) == 0) { /* Update time info for user */ users[userid].last_pkt = time(NULL); @@ -890,7 +847,7 @@ handle_raw_login(uint8_t *packet, size_t len, struct query *q, int fd, int useri /* Correct hash, reply with hash of seed - 1 */ user_set_conn_type(userid, CONN_RAW_UDP); - login_calculate(myhash, 16, password, users[userid].seed - 1); + login_calculate(myhash, 16, server.password, users[userid].seed - 1); send_raw(fd, (uint8_t *)myhash, 16, userid, RAW_HDR_CMD_LOGIN, &q->from, q->fromlen); users[userid].authenticated_raw = 1; @@ -898,7 +855,7 @@ handle_raw_login(uint8_t *packet, size_t len, struct query *q, int fd, int useri } static void -handle_raw_data(uint8_t *packet, size_t len, struct query *q, struct dnsfd *dns_fds, int tun_fd, int userid) +handle_raw_data(uint8_t *packet, size_t len, struct query *q, int userid) { if (check_authenticated_user_and_ip(userid, q) != 0) { return; @@ -912,7 +869,7 @@ handle_raw_data(uint8_t *packet, size_t len, struct query *q, struct dnsfd *dns_ DEBUG(3, "RX-raw: full pkt raw, length %lu, from user %d", len, userid); - handle_full_packet(tun_fd, dns_fds, userid, packet, len, 1); + handle_full_packet(userid, packet, len, 1); } static void @@ -933,7 +890,7 @@ handle_raw_ping(struct query *q, int dns_fd, int userid) } static int -raw_decode(uint8_t *packet, size_t len, struct query *q, int dns_fd, struct dnsfd *dns_fds, int tun_fd) +raw_decode(uint8_t *packet, size_t len, struct query *q, int dns_fd) { int raw_user; uint8_t raw_cmd; @@ -959,7 +916,7 @@ raw_decode(uint8_t *packet, size_t len, struct query *q, int dns_fd, struct dnsf break; case RAW_HDR_CMD_DATA: /* Data packet */ - handle_raw_data(packet, len, q, dns_fds, tun_fd, raw_user); + handle_raw_data(packet, len, q, raw_user); break; case RAW_HDR_CMD_PING: /* Keepalive packet */ @@ -973,8 +930,7 @@ raw_decode(uint8_t *packet, size_t len, struct query *q, int dns_fd, struct dnsf } int -read_dns(int fd, struct dnsfd *dns_fds, int tun_fd, struct query *q) -/* FIXME: dns_fds and tun_fd are because of raw_decode() below */ +read_dns(int fd, struct query *q) { struct sockaddr_storage from; socklen_t addrlen; @@ -1010,7 +966,7 @@ read_dns(int fd, struct dnsfd *dns_fds, int tun_fd, struct query *q) gettimeofday(&q->time_recv, NULL); /* TODO do not handle raw packets here! */ - if (raw_decode(packet, r, q, fd, dns_fds, tun_fd)) { + if (raw_decode(packet, r, q, fd)) { return 0; } if (dns_decode(NULL, 0, q, QR_QUERY, (char *)packet, r) < 0) { @@ -1173,7 +1129,7 @@ write_dns(int fd, struct query *q, char *data, size_t datalen, char downenc) } void -handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query *q, int domain_len) +handle_null_request(int dns_fd, struct query *q, int domain_len) /* Handles a NULL DNS request. See doc/proto_XXXXXXXX.txt for details on iodine protocol. */ { struct in_addr tempip; @@ -1269,20 +1225,20 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query return; } else { users[userid].last_pkt = time(NULL); - login_calculate(logindata, 16, password, users[userid].seed); + login_calculate(logindata, 16, server.password, users[userid].seed); if (read >= 18 && (memcmp(logindata, unpacked + 1, 16) == 0)) { /* Store login ok */ users[userid].authenticated = 1; /* Send ip/mtu/netmask info */ - tempip.s_addr = my_ip; + tempip.s_addr = server.my_ip; tmp[0] = strdup(inet_ntoa(tempip)); tempip.s_addr = users[userid].tun_ip; tmp[1] = strdup(inet_ntoa(tempip)); read = snprintf((char *)out, sizeof(out), "%s-%s-%d-%d", - tmp[0], tmp[1], my_mtu, netmask); + tmp[0], tmp[1], server.mtu, server.netmask); write_dns(dns_fd, q, (char *)out, read, users[userid].downenc); syslog(LOG_NOTICE, "accepted password from user #%d, given IP %s", userid, tmp[1]); @@ -1308,9 +1264,9 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query reply[0] = 'I'; if (q->from.ss_family == AF_INET) { - if (ns_ip != INADDR_ANY) { + if (server.ns_ip != INADDR_ANY) { /* If set, use assigned external ip (-n option) */ - memcpy(&reply[1], &ns_ip, sizeof(ns_ip)); + memcpy(&reply[1], &server.ns_ip, sizeof(server.ns_ip)); } else { /* otherwise return destination ip from packet */ struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination; @@ -1647,11 +1603,11 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query users[userid].outgoing->windowsize, dn_winsize, users[userid].incoming->windowsize, up_winsize); users[userid].outgoing->windowsize = dn_winsize; users[userid].incoming->windowsize = up_winsize; - send_data_or_ping(dns_fds, userid, q, 1, 1); + send_data_or_ping(userid, q, 1, 1); return; } - user_process_incoming_data(tun_fd, dns_fds, userid, dn_ack); + user_process_incoming_data(userid, dn_ack); /* if respond flag not set, query waits in qmem and is used later */ } else if (isxdigit(in[0])) { /* Upstream data packet */ @@ -1712,7 +1668,7 @@ handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query window_process_incoming_fragment(users[userid].incoming, &f); users[userid].next_upstream_ack = f.seqID; - user_process_incoming_data(tun_fd, dns_fds, userid, f.ack_other); + user_process_incoming_data(userid, f.ack_other); /* Nothing to do. ACK for this fragment is sent later in qmem_max_wait, * using an old query. This is left in qmem until needed/times out */ @@ -1727,14 +1683,14 @@ handle_ns_request(int dns_fd, struct query *q) char buf[64*1024]; int len; - if (ns_ip != INADDR_ANY) { + if (server.ns_ip != INADDR_ANY) { /* If ns_ip set, overwrite destination addr with it. * Destination addr will be sent as additional record (A, IN) */ struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination; - memcpy(&addr->sin_addr, &ns_ip, sizeof(ns_ip)); + memcpy(&addr->sin_addr, &server.ns_ip, sizeof(server.ns_ip)); } - len = dns_encode_ns_response(buf, sizeof(buf), q, topdomain); + len = dns_encode_ns_response(buf, sizeof(buf), q, server.topdomain); if (len < 1) { warnx("dns_encode_ns_response doesn't fit"); return; @@ -1759,11 +1715,11 @@ handle_a_request(int dns_fd, struct query *q, int fakeip) struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination; memcpy(&addr->sin_addr, &ip, sizeof(ip)); - } else if (ns_ip != INADDR_ANY) { + } else if (server.ns_ip != INADDR_ANY) { /* If ns_ip set, overwrite destination addr with it. * Destination addr will be sent as additional record (A, IN) */ struct sockaddr_in *addr = (struct sockaddr_in *) &q->destination; - memcpy(&addr->sin_addr, &ns_ip, sizeof(ns_ip)); + memcpy(&addr->sin_addr, &server.ns_ip, sizeof(server.ns_ip)); } len = dns_encode_a_response(buf, sizeof(buf), q); diff --git a/src/server.h b/src/server.h index 6183bf6..4024b4c 100644 --- a/src/server.h +++ b/src/server.h @@ -40,7 +40,7 @@ /* Max number of incoming queries to hold at one time (recommended to be same as windowsize) * Memory = USERS * (sizeof(struct query_buffer) + sizeof(query) * QMEM_LEN) */ -#define QMEM_LEN 24 +#define QMEM_LEN 32 #define USE_DNSCACHE /* QMEM entries contain additional space for DNS responses. @@ -57,6 +57,8 @@ #define PASSWORD_ENV_VAR "IODINED_PASS" +#define INSTANCE server + #if defined IP_RECVDSTADDR # define DSTADDR_SOCKOPT IP_RECVDSTADDR # define dstaddr(x) ((struct in_addr *) CMSG_DATA(x)) @@ -82,6 +84,38 @@ struct dnsfd { int v6fd; }; +struct server_instance { + /* Global server variables */ + int running; + char *topdomain; + char password[33]; + int check_ip; + int my_mtu; + in_addr_t my_ip; + int netmask; + in_addr_t ns_ip; + int bind_port; + int debug; + + int addrfamily; + struct dnsfd dns_fds; + int tun_fd; + int port; + int mtu; + int max_idle_time; + struct sockaddr_storage dns4addr; + int dns4addr_len; + struct sockaddr_storage dns6addr; + int dns6addr_len; + + /* settings for forwarding normal DNS to + * local real DNS server */ + int bind_fd; + int bind_enable; +}; + +extern struct server_instance server; + typedef enum { VERSION_ACK, VERSION_NACK, @@ -110,34 +144,17 @@ struct qmem_buffer { size_t num_pending; /* number of pending queries */ }; -extern char *topdomain; -extern char password[33]; -extern struct encoder *b32; -extern struct encoder *b64; -extern struct encoder *b64u; -extern struct encoder *b128; - -extern int check_ip; -extern int my_mtu; -extern in_addr_t my_ip; -extern int netmask; - -extern in_addr_t ns_ip; - -extern int bind_port; -extern int debug; - void server_init(); void server_stop(); -int server_tunnel(int tun_fd, struct dnsfd *dns_fds, int bind_fd, int max_idle_time); +int server_tunnel(); -int read_dns(int fd, struct dnsfd *dns_fds, int tun_fd, struct query *q); +int read_dns(int fd, struct query *q); void write_dns(int fd, struct query *q, char *data, size_t datalen, char downenc); -void handle_full_packet(int tun_fd, struct dnsfd *dns_fds, int userid, uint8_t *data, size_t len, int); -void handle_null_request(int tun_fd, int dns_fd, struct dnsfd *dns_fds, struct query *q, int domain_len); +void handle_full_packet(int userid, uint8_t *data, size_t len, int); +void handle_null_request(int dns_fd, struct query *q, int domain_len); void handle_ns_request(int dns_fd, struct query *q); void handle_a_request(int dns_fd, struct query *q, int fakeip); -void send_data_or_ping(struct dnsfd *, int, struct query *, int, int); +void send_data_or_ping(int, struct query *, int, int); #endif /* __SERVER_H__ */ diff --git a/src/user.c b/src/user.c index 6c4b69f..98aca0a 100644 --- a/src/user.c +++ b/src/user.c @@ -78,7 +78,7 @@ init_users(in_addr_t my_ip, int netbits) snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1); ip = ipstart.s_addr + inet_addr(newip); } - if (debug >= 2) { + if (server.debug >= 2) { struct in_addr IP; IP.s_addr = ip; DEBUG(2, "User %d: IP %s", i, inet_ntoa(IP)); @@ -201,7 +201,7 @@ check_user_and_ip(int userid, struct query *q) if (!user_active(userid)) return 1; /* return early if IP checking is disabled */ - if (!check_ip) { + if (!server.check_ip) { return 0; }