LTTNG_HIDDEN int run_as_mkdirat(int dirfd, const char *path, mode_t mode, uid_t uid, gid_t gid) { int ret; struct run_as_data data; struct run_as_ret run_as_ret; memset(&data, 0, sizeof(data)); memset(&run_as_ret, 0, sizeof(run_as_ret)); DBG3("mkdirat() recursive fd = %d%s, path = %s, mode = %d, uid = %d, gid = %d", dirfd, dirfd == AT_FDCWD ? " (AT_FDCWD)" : "", path, (int) mode, (int) uid, (int) gid); ret = lttng_strncpy(data.u.mkdirat.path, path, sizeof(data.u.mkdirat.path)); if (ret) { ERR("Failed to copy path argument of mkdirat command"); goto error; } data.u.mkdirat.path[PATH_MAX - 1] = '\0'; data.u.mkdirat.mode = mode; data.fd = dirfd; run_as(dirfd == AT_FDCWD ? RUN_AS_MKDIR : RUN_AS_MKDIRAT, &data, &run_as_ret, uid, gid); errno = run_as_ret._errno; ret = run_as_ret._errno; error: return ret; }
LTTNG_HIDDEN int run_as_extract_elf_symbol_offset(int fd, const char* function, uid_t uid, gid_t gid, uint64_t *offset) { struct run_as_data data; struct run_as_ret ret; memset(&data, 0, sizeof(data)); memset(&ret, 0, sizeof(ret)); DBG3("extract_elf_symbol_offset() on fd=%d and function=%s " "with for uid %d and gid %d", fd, function, (int) uid, (int) gid); data.fd = fd; strncpy(data.u.extract_elf_symbol_offset.function, function, LTTNG_SYMBOL_NAME_LEN - 1); data.u.extract_elf_symbol_offset.function[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; run_as(RUN_AS_EXTRACT_ELF_SYMBOL_OFFSET, &data, &ret, uid, gid); errno = ret._errno; if (ret._error) { return -1; } *offset = ret.u.extract_elf_symbol_offset.offset; return 0; }
LTTNG_HIDDEN int run_as_unlink(const char *path, uid_t uid, gid_t gid) { struct run_as_data data; DBG3("unlink() %s with for uid %d and gid %d", path, (int) uid, (int) gid); strncpy(data.u.unlink.path, path, PATH_MAX - 1); data.u.unlink.path[PATH_MAX - 1] = '\0'; return run_as(RUN_AS_UNLINK, &data, uid, gid); }
LTTNG_HIDDEN int run_as_rmdir_recursive(const char *path, uid_t uid, gid_t gid) { struct run_as_data data; DBG3("rmdir_recursive() %s with for uid %d and gid %d", path, (int) uid, (int) gid); strncpy(data.u.rmdir_recursive.path, path, PATH_MAX - 1); data.u.rmdir_recursive.path[PATH_MAX - 1] = '\0'; return run_as(RUN_AS_RMDIR_RECURSIVE, &data, uid, gid); }
void create() { ansid = find_object(ANSI_D); if (!ansid) { ansid = compile_object(ANSI_D); } set_property("auto_admin",0,"*","system"); set_property("auto_wiz",0,"*","system"); user_name = "Guest"; data_version = 1; run_as("nobody"); }
LTTNG_HIDDEN int run_as_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) { struct run_as_data data; DBG3("mkdir() %s with mode %d for uid %d and gid %d", path, (int) mode, (int) uid, (int) gid); strncpy(data.u.mkdir.path, path, PATH_MAX - 1); data.u.mkdir.path[PATH_MAX - 1] = '\0'; data.u.mkdir.mode = mode; return run_as(RUN_AS_MKDIR, &data, uid, gid); }
LTTNG_HIDDEN int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid) { struct run_as_data data; DBG3("open() %s with flags %X mode %d for uid %d and gid %d", path, flags, (int) mode, (int) uid, (int) gid); strncpy(data.u.open.path, path, PATH_MAX - 1); data.u.open.path[PATH_MAX - 1] = '\0'; data.u.open.flags = flags; data.u.open.mode = mode; return run_as(RUN_AS_OPEN, &data, uid, gid); }
LTTNG_HIDDEN int run_as_rmdir_recursive(const char *path, uid_t uid, gid_t gid) { struct run_as_data data; struct run_as_ret ret; memset(&data, 0, sizeof(data)); memset(&ret, 0, sizeof(ret)); DBG3("rmdir_recursive() %s with for uid %d and gid %d", path, (int) uid, (int) gid); strncpy(data.u.rmdir_recursive.path, path, PATH_MAX - 1); data.u.rmdir_recursive.path[PATH_MAX - 1] = '\0'; run_as(RUN_AS_RMDIR_RECURSIVE, &data, &ret, uid, gid); errno = ret._errno; return ret.u.rmdir_recursive.ret; }
LTTNG_HIDDEN int run_as_unlink(const char *path, uid_t uid, gid_t gid) { struct run_as_data data; struct run_as_ret ret; memset(&data, 0, sizeof(data)); memset(&ret, 0, sizeof(ret)); DBG3("unlink() %s with for uid %d and gid %d", path, (int) uid, (int) gid); strncpy(data.u.unlink.path, path, PATH_MAX - 1); data.u.unlink.path[PATH_MAX - 1] = '\0'; run_as(RUN_AS_UNLINK, &data, &ret, uid, gid); errno = ret._errno; return ret.u.unlink.ret; }
LTTNG_HIDDEN int run_as_open(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid) { struct run_as_data data; struct run_as_ret ret; memset(&data, 0, sizeof(data)); memset(&ret, 0, sizeof(ret)); DBG3("open() %s with flags %X mode %d for uid %d and gid %d", path, flags, (int) mode, (int) uid, (int) gid); strncpy(data.u.open.path, path, PATH_MAX - 1); data.u.open.path[PATH_MAX - 1] = '\0'; data.u.open.flags = flags; data.u.open.mode = mode; run_as(RUN_AS_OPEN, &data, &ret, uid, gid); errno = ret._errno; ret.u.open.ret = ret.fd; return ret.u.open.ret; }
LTTNG_HIDDEN int run_as_extract_sdt_probe_offsets(int fd, const char* provider_name, const char* probe_name, uid_t uid, gid_t gid, uint64_t **offsets, uint32_t *num_offset) { struct run_as_data data; struct run_as_ret ret; memset(&data, 0, sizeof(data)); memset(&ret, 0, sizeof(ret)); DBG3("extract_sdt_probe_offsets() on fd=%d, probe_name=%s and " "provider_name=%s with for uid %d and gid %d", fd, probe_name, provider_name, (int) uid, (int) gid); data.fd = fd; strncpy(data.u.extract_sdt_probe_offsets.probe_name, probe_name, LTTNG_SYMBOL_NAME_LEN - 1); strncpy(data.u.extract_sdt_probe_offsets.provider_name, provider_name, LTTNG_SYMBOL_NAME_LEN - 1); data.u.extract_sdt_probe_offsets.probe_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; data.u.extract_sdt_probe_offsets.provider_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0'; run_as(RUN_AS_EXTRACT_SDT_PROBE_OFFSETS, &data, &ret, uid, gid); errno = ret._errno; if (ret._error) { return -1; } *num_offset = ret.u.extract_sdt_probe_offsets.num_offset; *offsets = zmalloc(*num_offset * sizeof(uint64_t)); if (!*offsets) { return -ENOMEM; } memcpy(*offsets, ret.u.extract_sdt_probe_offsets.offsets, *num_offset * sizeof(uint64_t)); return 0; }
int main (int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; int server_num = 0; const char *server_host[MAX_REMOTE_NUM]; const char *server_port = NULL; int dns_thread_num = DNS_THREAD_NUM; int option_index = 0; static struct option long_options[] = { {"fast-open", no_argument, 0, 0 }, {"port-start", required_argument, 0, 0 }, {"port-end", required_argument, 0, 0 }, {0, 0, 0, 0 } }; opterr = 0; while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:i:d:a:uv", long_options, &option_index)) != -1) { printf("option_index %d\n", option_index); switch (c) { case 0: if (option_index == 0) { #ifdef TCP_FASTOPEN fast_open = 1; LOGD("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); #endif } else if (option_index == 1) { start_port = atoi(optarg); } else if (option_index == 2) { end_port = atoi(optarg); } break; case 's': server_host[server_num++] = optarg; break; case 'p': server_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'd': dns_thread_num = atoi(optarg); if (!dns_thread_num) FATAL("Invalid DNS thread number"); break; case 'a': user = optarg; break; case 'u': udprelay = 1; break; case 'v': verbose = 1; break; } } printf("start %d end %d\n", start_port, end_port); if (opterr) { usage(); exit(EXIT_FAILURE); } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (server_num == 0) { server_num = conf->remote_num; for (i = 0; i < server_num; i++) { server_host[i] = conf->remote_addr[i].host; } } if (server_port == NULL) server_port = conf->remote_port; if (password == NULL) password = conf->password; if (method == NULL) method = conf->method; if (timeout == NULL) timeout = conf->timeout; #ifdef TCP_FASTOPEN if (fast_open == 0) fast_open = conf->fast_open; #endif #ifdef HAVE_SETRLIMIT if (nofile == 0) nofile = conf->nofile; /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile) { if (verbose) { LOGD("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif } if ((start_port > 0 && end_port <= 0) || (start_port <= 0 && end_port > 0)) { printf("Both start_prot and end_port needs to be specified\n"); usage(); exit(EXIT_FAILURE); } if (server_port != NULL && start_port > 0) { printf("server port can't be set if you want to use a port range\n"); usage(); exit(EXIT_FAILURE); } if (server_num == 0 || (server_port == NULL && start_port <= 0) || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) timeout = "60"; if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); signal(SIGABRT, SIG_IGN); // setup asyncns asyncns_t *asyncns; if (!(asyncns = asyncns_new(dns_thread_num))) { FATAL("asyncns failed"); } // setup keys LOGD("initialize ciphers... %s", method); int m = enc_init(password, method); // inilitialize ev loop struct ev_loop *loop = EV_DEFAULT; // inilitialize listen context struct listen_ctx listen_ctx_list[server_num + 1]; // bind to each interface while (server_num > 0) { int index = --server_num; const char* host = server_host[index]; int success = 1; int listenfd; if (start_port > 0) { server_port = itoa(start_port); } do { // Bind to port listenfd = create_and_bind(host, server_port); success = 1; if (listenfd < 0) { success = 0; } if (listen(listenfd, SOMAXCONN) == -1) { success = 0; } if (!success) { if (start_port < end_port) { start_port++; server_port = itoa(start_port); } else { FATAL("Out of listen ports!"); exit(1); } } } while (!success); setnonblocking(listenfd); LOGD("server listening at port %s.", server_port); struct listen_ctx *listen_ctx = &listen_ctx_list[index + 1]; // Setup proxy context listen_ctx->timeout = atoi(timeout); listen_ctx->asyncns = asyncns; listen_ctx->fd = listenfd; listen_ctx->method = m; listen_ctx->iface = iface; ev_io_init (&listen_ctx->io, accept_cb, listenfd, EV_READ); ev_io_start (loop, &listen_ctx->io); } // initialize the DNS struct listen_ctx *listen_ctx = &listen_ctx_list[0]; int asyncnsfd = asyncns_fd(asyncns); listen_ctx->timeout = atoi(timeout); listen_ctx->asyncns = asyncns; listen_ctx->fd = asyncnsfd; listen_ctx->method = m; listen_ctx->iface = iface; ev_io_init (&listen_ctx->io, server_resolve_cb, asyncnsfd, EV_READ); ev_io_start (loop, &listen_ctx->io); // Setup UDP if (udprelay) { LOGD("udprelay enabled."); udprelay_init(server_host[0], server_port, dns_thread_num, m, listen_ctx->timeout, iface); } // setuid if (user != NULL) run_as(user); // start ev loop ev_run (loop, 0); return 0; }
int main(int argc, char **argv) { srand(time(NULL)); int i, c; int pid_flags = 0; int mptcp = 0; int mtu = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *key = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *plugin = NULL; char *plugin_opts = NULL; char *plugin_host = NULL; char *plugin_port = NULL; char tmp_port[8]; int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; int dscp_num = 0; ss_dscp_t * dscp = NULL; static struct option long_options[] = { { "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN }, { "mtu", required_argument, NULL, GETOPT_VAL_MTU }, { "mptcp", no_argument, NULL, GETOPT_VAL_MPTCP }, { "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN }, { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, { "no-delay", no_argument, NULL, GETOPT_VAL_NODELAY }, { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, { "key", required_argument, NULL, GETOPT_VAL_KEY }, { "help", no_argument, NULL, GETOPT_VAL_HELP }, { NULL, 0, NULL, 0 } }; opterr = 0; USE_TTY(); while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:b:a:n:huUv6A", long_options, NULL)) != -1) { switch (c) { case GETOPT_VAL_FAST_OPEN: fast_open = 1; break; case GETOPT_VAL_MTU: mtu = atoi(optarg); LOGI("set MTU to %d", mtu); break; case GETOPT_VAL_MPTCP: mptcp = 1; LOGI("enable multipath TCP"); break; case GETOPT_VAL_NODELAY: no_delay = 1; LOGI("enable TCP no-delay"); break; case GETOPT_VAL_PLUGIN: plugin = optarg; break; case GETOPT_VAL_PLUGIN_OPTS: plugin_opts = optarg; break; case GETOPT_VAL_KEY: key = optarg; break; case GETOPT_VAL_REUSE_PORT: reuse_port = 1; break; case 's': if (remote_num < MAX_REMOTE_NUM) { remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case GETOPT_VAL_PASSWORD: case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; #ifdef HAVE_SETRLIMIT case 'n': nofile = atoi(optarg); break; #endif case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'v': verbose = 1; break; case GETOPT_VAL_HELP: case 'h': usage(); exit(EXIT_SUCCESS); case '6': ipv6first = 1; break; case 'A': FATAL("One time auth has been deprecated. Try AEAD ciphers instead."); break; case '?': // The option character is not recognized. LOGE("Unrecognized option: %s", optarg); opterr = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) remote_addr[i] = conf->remote_addr[i]; } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (key == NULL) { key = conf->key; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (user == NULL) { user = conf->user; } if (plugin == NULL) { plugin = conf->plugin; } if (plugin_opts == NULL) { plugin_opts = conf->plugin_opts; } if (mode == TCP_ONLY) { mode = conf->mode; } if (mtu == 0) { mtu = conf->mtu; } if (mptcp == 0) { mptcp = conf->mptcp; } if (reuse_port == 0) { reuse_port = conf->reuse_port; } if (disable_sni == 0) { disable_sni = conf->disable_sni; } if (fast_open == 0) { fast_open = conf->fast_open; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } #endif if (ipv6first == 0) { ipv6first = conf->ipv6_first; } dscp_num = conf->dscp_num; dscp = conf->dscp; } if (remote_num == 0 || remote_port == NULL || local_port == NULL || (password == NULL && key == NULL)) { usage(); exit(EXIT_FAILURE); } if (plugin != NULL) { uint16_t port = get_local_port(); if (port == 0) { FATAL("failed to find a free port"); } snprintf(tmp_port, 8, "%d", port); plugin_host = "127.0.0.1"; plugin_port = tmp_port; LOGI("plugin \"%s\" enabled", plugin); } if (method == NULL) { method = "rc4-md5"; } if (timeout == NULL) { timeout = "600"; } #ifdef HAVE_SETRLIMIT /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile > 1024) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif if (local_addr == NULL) { local_addr = "127.0.0.1"; } if (fast_open == 1) { #ifdef TCP_FASTOPEN LOGI("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); fast_open = 0; #endif } USE_SYSLOG(argv[0], pid_flags); if (pid_flags) { daemonize(pid_path); } if (ipv6first) { LOGI("resolving hostname to IPv6 address first"); } if (plugin != NULL) { int len = 0; size_t buf_size = 256 * remote_num; char *remote_str = ss_malloc(buf_size); snprintf(remote_str, buf_size, "%s", remote_addr[0].host); for (int i = 1; i < remote_num; i++) { snprintf(remote_str + len, buf_size - len, "|%s", remote_addr[i].host); len = strlen(remote_str); } int err = start_plugin(plugin, plugin_opts, remote_str, remote_port, plugin_host, plugin_port, MODE_CLIENT); if (err) { FATAL("failed to start the plugin"); } } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_init(&sigchld_watcher, signal_cb, SIGCHLD); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); ev_signal_start(EV_DEFAULT, &sigchld_watcher); // Setup keys LOGI("initializing ciphers... %s", method); crypto = crypto_init(password, key, method); if (crypto == NULL) FATAL("failed to initialize ciphers"); // Setup proxy context struct listen_ctx listen_ctx; memset(&listen_ctx, 0, sizeof(struct listen_ctx)); listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = ss_malloc(sizeof(struct sockaddr *) * remote_num); memset(listen_ctx.remote_addr, 0, sizeof(struct sockaddr *) * remote_num); for (i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; if (plugin != NULL) { host = plugin_host; port = plugin_port; } struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; if (plugin != NULL) break; } listen_ctx.timeout = atoi(timeout); listen_ctx.mptcp = mptcp; struct ev_loop *loop = EV_DEFAULT; listen_ctx_t* listen_ctx_current = &listen_ctx; do { if (mode != UDP_ONLY) { // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd == -1) { FATAL("bind() error"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); listen_ctx_current->fd = listenfd; ev_io_init(&listen_ctx_current->io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx_current->io); } // Setup UDP if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); char *host = remote_addr[0].host; char *port = remote_addr[0].port == NULL ? remote_port : remote_addr[0].port; struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) { FATAL("failed to resolve the provided hostname"); } struct sockaddr *addr = (struct sockaddr *)storage; init_udprelay(local_addr, local_port, addr, get_sockaddr_len(addr), mtu, crypto, listen_ctx_current->timeout, NULL); } if (mode == UDP_ONLY) { LOGI("TCP relay disabled"); } if(listen_ctx_current->tos) { LOGI("listening at %s:%s (TOS 0x%x)", local_addr, local_port, listen_ctx_current->tos); } else { LOGI("listening at %s:%s", local_addr, local_port); } // Handle additionals TOS/DSCP listening ports if (dscp_num > 0) { listen_ctx_current = (listen_ctx_t*) ss_malloc(sizeof(listen_ctx_t)); listen_ctx_current = memcpy(listen_ctx_current, &listen_ctx, sizeof(listen_ctx_t)); local_port = dscp[dscp_num-1].port; listen_ctx_current->tos = dscp[dscp_num-1].dscp << 2; } } while (dscp_num-- > 0); // setuid if (user != NULL && !run_as(user)) { FATAL("failed to switch user"); } if (geteuid() == 0) { LOGI("running from root user"); } ev_run(loop, 0); if (plugin != NULL) { stop_plugin(); } return 0; }
int main(int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; opterr = 0; while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:c:b:a:n:uUvA")) != -1) switch (c) { case 's': if (remote_num < MAX_REMOTE_NUM) { remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; #ifdef HAVE_SETRLIMIT case 'n': nofile = atoi(optarg); break; #endif case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'v': verbose = 1; break; case 'A': auth = 1; break; } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) remote_addr[i] = conf->remote_addr[i]; } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (auth == 0) { auth = conf->auth; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile > 1024) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif } if (remote_num == 0 || remote_port == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) { timeout = "60"; } if (local_addr == NULL) { local_addr = "127.0.0.1"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } if (auth) { LOGI("onetime authentication enabled"); } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); // Setup keys LOGI("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup proxy context listen_ctx_t listen_ctx; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *) * remote_num); for (int i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; } listen_ctx.timeout = atoi(timeout); listen_ctx.method = m; struct ev_loop *loop = EV_DEFAULT; if (mode != UDP_ONLY) { // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd < 0) { FATAL("bind() error"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); } // Setup UDP if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0], get_sockaddr_len(listen_ctx.remote_addr[0]), m, auth, listen_ctx.timeout, NULL); } if (mode == UDP_ONLY) { LOGI("TCP relay disabled"); } LOGI("listening at %s:%s", local_addr, local_port); // setuid if (user != NULL) { run_as(user); } ev_run(loop, 0); return 0; }
int main(int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; srand(time(NULL)); int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; int option_index = 0; static struct option long_options[] = { { "fast-open", no_argument, 0, 0 }, { "acl", required_argument, 0, 0 }, { 0, 0, 0, 0 } }; opterr = 0; while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uv", long_options, &option_index)) != -1) { switch (c) { case 0: if (option_index == 0) { fast_open = 1; } else if (option_index == 1) { LOGD("initialize acl..."); acl = !init_acl(optarg); } break; case 's': remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; case 'u': udprelay = 1; break; case 'v': verbose = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) { remote_addr[i] = conf->remote_addr[i]; } } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (fast_open == 0) { fast_open = conf->fast_open; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile) { if (verbose) { LOGD("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif } if (remote_num == 0 || remote_port == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) { timeout = "10"; } if (local_addr == NULL) { local_addr = "0.0.0.0"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } if (fast_open == 1) { #ifdef TCP_FASTOPEN LOGD("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); #endif } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif struct ev_signal sigint_watcher; struct ev_signal sigterm_watcher; ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); // Setup keys LOGD("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd < 0) { FATAL("bind() error.."); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error."); } setnonblocking(listenfd); LOGD("server listening at port %s.", local_port); // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = malloc(sizeof(ss_addr_t) * remote_num); while (remote_num > 0) { int index = --remote_num; if (remote_addr[index].port == NULL) { remote_addr[index].port = remote_port; } listen_ctx.remote_addr[index] = remote_addr[index]; } listen_ctx.timeout = atoi(timeout); listen_ctx.fd = listenfd; listen_ctx.iface = iface; listen_ctx.method = m; struct ev_loop *loop = EV_DEFAULT; if (!loop) { FATAL("ev_loop error."); } ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); // Setup UDP if (udprelay) { LOGD("udprelay enabled."); init_udprelay(local_addr, local_port, remote_addr[0].host, remote_addr[0].port, m, listen_ctx.timeout, iface); } // setuid if (user != NULL) { run_as(user); } // Init connections cork_dllist_init(&connections); // Enter the loop ev_run(loop, 0); if (verbose) { LOGD("closed nicely."); } // Clean up free_connections(loop); free_udprelay(); ev_io_stop(loop, &listen_ctx.io); free(listen_ctx.remote_addr); #ifdef __MINGW32__ winsock_cleanup(); #endif ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); return 0; }
int main(int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; int server_num = 0; const char *server_host[MAX_REMOTE_NUM]; char * nameservers[MAX_DNS_NUM + 1]; int nameserver_num = 0; int option_index = 0; static struct option long_options[] = { { "fast-open", no_argument, 0, 0 }, { "acl", required_argument, 0, 0 }, { "manager-address", required_argument, 0, 0 }, { 0, 0, 0, 0 } }; opterr = 0; USE_TTY(); while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:i:d:a:uUv", long_options, &option_index)) != -1) { switch (c) { case 0: if (option_index == 0) { fast_open = 1; } else if (option_index == 1) { LOGI("initialize acl..."); acl = !init_acl(optarg); } else if (option_index == 2) { manager_address = optarg; } break; case 's': if (server_num < MAX_REMOTE_NUM) { server_host[server_num++] = optarg; } break; case 'p': server_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'd': if (nameserver_num < MAX_DNS_NUM) { nameservers[nameserver_num++] = optarg; } break; case 'a': user = optarg; break; case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'v': verbose = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (server_num == 0) { server_num = conf->remote_num; for (i = 0; i < server_num; i++) { server_host[i] = conf->remote_addr[i].host; } } if (server_port == NULL) { server_port = conf->remote_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } #ifdef TCP_FASTOPEN if (fast_open == 0) { fast_open = conf->fast_open; } #endif #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif if (conf->nameserver != NULL) { nameservers[nameserver_num++] = conf->nameserver; } } if (server_num == 0) { server_host[server_num++] = NULL; } if (server_num == 0 || server_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (method == NULL) { method = "table"; } if (timeout == NULL) { timeout = "60"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } if (fast_open == 1) { #ifdef TCP_FASTOPEN LOGI("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); #endif } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif struct ev_signal sigint_watcher; struct ev_signal sigterm_watcher; ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); // setup keys LOGI("initialize ciphers... %s", method); int m = enc_init(password, method); // inilitialize ev loop struct ev_loop *loop = EV_DEFAULT; // setup udns if (nameserver_num == 0) { #ifdef __MINGW32__ nameservers[nameserver_num++] = "8.8.8.8"; resolv_init(loop, nameservers, nameserver_num); #else resolv_init(loop, NULL, 0); #endif } else { resolv_init(loop, nameservers, nameserver_num); } for (int i = 0; i < nameserver_num; i++) { LOGI("using nameserver: %s", nameservers[i]); } // inilitialize listen context struct listen_ctx listen_ctx_list[server_num]; // bind to each interface while (server_num > 0) { int index = --server_num; const char * host = server_host[index]; if (mode != UDP_ONLY) { // Bind to port int listenfd; listenfd = create_and_bind(host, server_port); if (listenfd < 0) { FATAL("bind() error"); } if (listen(listenfd, SSMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); struct listen_ctx *listen_ctx = &listen_ctx_list[index]; // Setup proxy context listen_ctx->timeout = atoi(timeout); listen_ctx->fd = listenfd; listen_ctx->method = m; listen_ctx->iface = iface; listen_ctx->loop = loop; ev_io_init(&listen_ctx->io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx->io); } // Setup UDP if (mode != TCP_ONLY) { init_udprelay(server_host[index], server_port, m, atoi(timeout), iface); } LOGI("listening at %s:%s", host ? host : "*", server_port); } if (manager_address != NULL) { ev_timer_init(&stat_update_watcher, stat_update_cb, UPDATE_INTERVAL, UPDATE_INTERVAL); ev_timer_start(EV_DEFAULT, &stat_update_watcher); } if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); } if (mode == UDP_ONLY) { LOGI("TCP relay disabled"); } // setuid if (user != NULL) { run_as(user); } // Init connections cork_dllist_init(&connections); // start ev loop ev_run(loop, 0); if (verbose) { LOGI("closed gracefully"); } if (manager_address != NULL) { ev_timer_stop(EV_DEFAULT, &stat_update_watcher); } // Clean up for (int i = 0; i <= server_num; i++) { struct listen_ctx *listen_ctx = &listen_ctx_list[i]; if (mode != UDP_ONLY) { ev_io_stop(loop, &listen_ctx->io); close(listen_ctx->fd); } } if (mode != UDP_ONLY) { free_connections(loop); } if (mode != TCP_ONLY) { free_udprelay(); } resolv_shutdown(loop); #ifdef __MINGW32__ winsock_cleanup(); #endif ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); return 0; }
/// does it. int as_modet::doit() { if(cmdline.isset('?') || cmdline.isset("help")) { help(); return EX_OK; } unsigned int verbosity=1; bool act_as_as86= base_name=="as86" || base_name.find("goto-as86")!=std::string::npos; if((cmdline.isset('v') && act_as_as86) || cmdline.isset("version")) { if(act_as_as86) status() << "as86 version: 0.16.17 (goto-cc " CBMC_VERSION ")" << eom; else status() << "GNU assembler version 2.20.51.0.7 20100318" << " (goto-cc " CBMC_VERSION ")" << eom; status() << '\n' << "Copyright (C) 2006-2014 Daniel Kroening, Christoph Wintersteiger\n" << "CBMC version: " CBMC_VERSION << '\n' << "Architecture: " << config.this_architecture() << '\n' << "OS: " << config.this_operating_system() << eom; return EX_OK; // Exit! } if(cmdline.isset("w-") || cmdline.isset("warn")) verbosity=2; if(cmdline.isset("verbosity")) verbosity=unsafe_string2unsigned(cmdline.get_value("verbosity")); message_handler.set_verbosity(verbosity); if(act_as_as86) { if(produce_hybrid_binary) debug() << "AS86 mode (hybrid)" << eom; else debug() << "AS86 mode" << eom; } else { if(produce_hybrid_binary) debug() << "AS mode (hybrid)" << eom; else debug() << "AS mode" << eom; } // get configuration config.set(cmdline); // determine actions to be undertaken compilet compiler(cmdline, message_handler, cmdline.isset("fatal-warnings")); if(cmdline.isset('b')) // as86 only { compiler.mode=compilet::COMPILE_LINK_EXECUTABLE; debug() << "Compiling and linking an executable" << eom; } else { compiler.mode=compilet::COMPILE_LINK; debug() << "Compiling and linking a library" << eom; } config.ansi_c.mode=configt::ansi_ct::flavourt::GCC; compiler.object_file_extension="o"; if(cmdline.isset('o')) { compiler.output_file_object=cmdline.get_value('o'); compiler.output_file_executable=cmdline.get_value('o'); } else if(cmdline.isset('b')) // as86 only { compiler.output_file_object=cmdline.get_value('b'); compiler.output_file_executable=cmdline.get_value('b'); } else { compiler.output_file_object="a.out"; compiler.output_file_executable="a.out"; } // We now iterate over any input files temp_dirt temp_dir("goto-cc-XXXXXX"); for(goto_cc_cmdlinet::parsed_argvt::iterator arg_it=cmdline.parsed_argv.begin(); arg_it!=cmdline.parsed_argv.end(); arg_it++) { if(!arg_it->is_infile_name) continue; // extract the preprocessed source from the file std::string infile=arg_it->arg=="-"?cmdline.stdin_file:arg_it->arg; std::ifstream is(infile); if(!is.is_open()) { error() << "Failed to open input source " << infile << eom; return 1; } // there could be multiple source files in case GCC's --combine // was used unsigned outputs=0; std::string line; std::ofstream os; std::string dest; const std::string comment2=act_as_as86 ? "::" : "##"; // search for comment2 GOTO-CC // strip comment2 from all subsequent lines while(std::getline(is, line)) { if(line==comment2+" GOTO-CC") { if(outputs>0) { assert(!dest.empty()); compiler.add_input_file(dest); os.close(); } ++outputs; std::string new_name= get_base_name(infile, true)+"_"+ std::to_string(outputs)+".i"; dest=temp_dir(new_name); os.open(dest); if(!os.is_open()) { error() << "Failed to tmp output file " << dest << eom; return 1; } continue; } else if(outputs==0) continue; if(line.size()>2) os << line.substr(2) << '\n'; } if(outputs>0) { assert(!dest.empty()); compiler.add_input_file(dest); } else warning() << "No GOTO-CC section found in " << arg_it->arg << eom; } // Revert to as in case there is no source to compile if(compiler.source_files.empty()) return run_as(); // exit! // do all the rest if(compiler.doit()) return 1; // GCC exit code for all kinds of errors // We can generate hybrid ELF and Mach-O binaries // containing both executable machine code and the goto-binary. if(produce_hybrid_binary) return as_hybrid_binary(); return EX_OK; }
int as_modet::as_hybrid_binary() { std::string output_file="a.out"; if(cmdline.isset('o')) { output_file=cmdline.get_value('o'); } else if(cmdline.isset('b')) // as86 only output_file=cmdline.get_value('b'); if(output_file=="/dev/null") return EX_OK; debug() << "Running " << native_tool_name << " to generate hybrid binary" << eom; // save the goto-cc output file rename(output_file.c_str(), (output_file+".goto-cc-saved").c_str()); int result=run_as(); // merge output from as with goto-binaries // using objcopy, or do cleanup if an earlier call failed debug() << "merging " << output_file << eom; std::string saved=output_file+".goto-cc-saved"; #ifdef __linux__ if(result==0) { // remove any existing goto-cc section std::vector<std::string> objcopy_argv; objcopy_argv.push_back("objcopy"); objcopy_argv.push_back("--remove-section=goto-cc"); objcopy_argv.push_back(output_file); result=run(objcopy_argv[0], objcopy_argv, "", ""); } if(result==0) { // now add goto-binary as goto-cc section std::vector<std::string> objcopy_argv; objcopy_argv.push_back("objcopy"); objcopy_argv.push_back("--add-section"); objcopy_argv.push_back("goto-cc="+saved); objcopy_argv.push_back(output_file); result=run(objcopy_argv[0], objcopy_argv, "", ""); } remove(saved.c_str()); #elif defined(__APPLE__) // Mac if(result==0) { std::vector<std::string> lipo_argv; // now add goto-binary as hppa7100LC section lipo_argv.push_back("lipo"); lipo_argv.push_back(output_file); lipo_argv.push_back("-create"); lipo_argv.push_back("-arch"); lipo_argv.push_back("hppa7100LC"); lipo_argv.push_back(saved); lipo_argv.push_back("-output"); lipo_argv.push_back(output_file); result=run(lipo_argv[0], lipo_argv, "", ""); } remove(saved.c_str()); #else error() << "binary merging not implemented for this platform" << eom; return 1; #endif return result; }
int main(int argc, char *argv[]) { struct sockaddr_in from; struct stat st; char path[64]; int on = 1; char *cp; struct sockaddr_in soin; uid_t unpriv_uid; gid_t unpriv_gid; if (getuid()) errx(1, "not super user"); run_as(&unpriv_uid, &unpriv_gid); argv++; argc--; while (argc > 0 && *argv[0] == '-') { if (strcmp(*argv, "-m") == 0) { if (argc > 1 && isdigit(*(argv + 1)[0])) { argv++, argc--; multicast_mode = SCOPED_MULTICAST; multicast_scope = atoi(*argv); if (multicast_scope > MAX_MULTICAST_SCOPE) errx(1, "ttl must not exceed %u", MAX_MULTICAST_SCOPE); } else multicast_mode = PER_INTERFACE_MULTICAST; } else if (strcmp(*argv, "-i") == 0) insecure_mode = 1; else if (strcmp(*argv, "-l") == 0) quiet_mode = 1; else if (strcmp(*argv, "-p") == 0) iff_flag = 0; else usage(); argv++, argc--; } if (argc > 0) usage(); #ifndef DEBUG daemon(1, 0); #endif (void) signal(SIGHUP, getboottime); openlog("rwhod", LOG_PID, LOG_DAEMON); sp = getservbyname("who", "udp"); if (sp == NULL) { syslog(LOG_ERR, "who/udp: unknown service"); exit(1); } if (chdir(_PATH_RWHODIR) < 0) { syslog(LOG_ERR, "%s: %m", _PATH_RWHODIR); exit(1); } /* * Establish host name as returned by system. */ if (gethostname(myname, sizeof(myname) - 1) < 0) { syslog(LOG_ERR, "gethostname: %m"); exit(1); } if ((cp = index(myname, '.')) != NULL) *cp = '\0'; strncpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname) - 1); mywd.wd_hostname[sizeof(mywd.wd_hostname) - 1] = '\0'; #ifdef __APPLE__ utmpf = open(_PATH_UTMPX, O_RDONLY|O_CREAT, 0644); #else utmpf = open(_PATH_UTMP, O_RDONLY|O_CREAT, 0644); #endif if (utmpf < 0) { #ifdef __APPLE__ syslog(LOG_ERR, "%s: %m", _PATH_UTMPX); #else syslog(LOG_ERR, "%s: %m", _PATH_UTMP); #endif exit(1); } getboottime(0); if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "socket: %m"); exit(1); } if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); exit(1); } memset(&soin, 0, sizeof(soin)); soin.sin_len = sizeof(soin); soin.sin_family = AF_INET; soin.sin_port = sp->s_port; if (bind(s, (struct sockaddr *)&soin, sizeof(soin)) < 0) { syslog(LOG_ERR, "bind: %m"); exit(1); } setgid(unpriv_gid); setgroups(1, &unpriv_gid); /* XXX BOGUS groups[0] = egid */ setuid(unpriv_uid); if (!configure(s)) exit(1); if (!quiet_mode) { signal(SIGALRM, onalrm); onalrm(0); } for (;;) { struct whod wd; socklen_t len = sizeof(from); int cc, whod; time_t t; cc = recvfrom(s, (char *)&wd, sizeof(struct whod), 0, (struct sockaddr *)&from, &len); if (cc <= 0) { if (cc < 0 && errno != EINTR) syslog(LOG_WARNING, "recv: %m"); continue; } if (from.sin_port != sp->s_port && !insecure_mode) { syslog(LOG_WARNING, "%d: bad source port from %s", ntohs(from.sin_port), inet_ntoa(from.sin_addr)); continue; } if (cc < WHDRSIZE) { syslog(LOG_WARNING, "short packet from %s", inet_ntoa(from.sin_addr)); continue; } if (wd.wd_vers != WHODVERSION) continue; if (wd.wd_type != WHODTYPE_STATUS) continue; if (!verify(wd.wd_hostname, sizeof wd.wd_hostname)) { syslog(LOG_WARNING, "malformed host name from %s", inet_ntoa(from.sin_addr)); continue; } (void) snprintf(path, sizeof path, "whod.%s", wd.wd_hostname); /* * Rather than truncating and growing the file each time, * use ftruncate if size is less than previous size. */ whod = open(path, O_WRONLY | O_CREAT, 0644); if (whod < 0) { syslog(LOG_WARNING, "%s: %m", path); continue; } #if ENDIAN != BIG_ENDIAN { int i, n = (cc - WHDRSIZE)/sizeof(struct whoent); struct whoent *we; /* undo header byte swapping before writing to file */ wd.wd_sendtime = ntohl(wd.wd_sendtime); for (i = 0; i < 3; i++) wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]); wd.wd_boottime = ntohl(wd.wd_boottime); we = wd.wd_we; for (i = 0; i < n; i++) { we->we_idle = ntohl(we->we_idle); we->we_utmp.out_time = ntohl(we->we_utmp.out_time); we++; } } #endif (void) time(&t); wd.wd_recvtime = _time_to_int(t); (void) write(whod, (char *)&wd, cc); if (fstat(whod, &st) < 0 || st.st_size > cc) ftruncate(whod, cc); (void) close(whod); } }
int main(int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; ss_addr_t tunnel_addr = { .host = NULL, .port = NULL }; char *tunnel_addr_str = NULL; opterr = 0; USE_TTY(); #ifdef ANDROID while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:uUvV")) != -1) { #else while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:i:c:b:L:a:uUv")) != -1) { #endif switch (c) { case 's': if (remote_num < MAX_REMOTE_NUM) { remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'b': local_addr = optarg; break; case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'L': tunnel_addr_str = optarg; break; case 'a': user = optarg; break; case 'v': verbose = 1; break; #ifdef ANDROID case 'V': vpn = 1; break; #endif } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) { remote_addr[i] = conf->remote_addr[i]; } } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } } if (remote_num == 0 || remote_port == NULL || tunnel_addr_str == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) { timeout = "60"; } if (local_addr == NULL) { local_addr = "127.0.0.1"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } // parse tunnel addr parse_addr(tunnel_addr_str, &tunnel_addr); if (tunnel_addr.port == NULL) { FATAL("tunnel port is not defined"); } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif // Setup keys LOGI("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.tunnel_addr = tunnel_addr; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *) * remote_num); for (i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; } listen_ctx.timeout = atoi(timeout); listen_ctx.iface = iface; listen_ctx.method = m; struct ev_loop *loop = EV_DEFAULT; if (mode != UDP_ONLY) { // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd < 0) { FATAL("bind() error:"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error:"); } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); } // Setup UDP if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0], get_sockaddr_len(listen_ctx.remote_addr[0]), tunnel_addr, m, listen_ctx.timeout, iface); } if (mode == UDP_ONLY) { LOGI("TCP relay disabled"); } LOGI("listening at %s:%s", local_addr, local_port); // setuid if (user != NULL) { run_as(user); } ev_run(loop, 0); #ifdef __MINGW32__ winsock_cleanup(); #endif return 0; }
int main (int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; opterr = 0; while ((c = getopt (argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uv")) != -1) { switch (c) { case 's': remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; case 'u': udprelay = 1; break; case 'v': verbose = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) { remote_addr[i] = conf->remote_addr[i]; } } if (remote_port == NULL) remote_port = conf->remote_port; if (local_addr == NULL) local_addr = conf->local_addr; if (local_port == NULL) local_port = conf->local_port; if (password == NULL) password = conf->password; if (method == NULL) method = conf->method; if (timeout == NULL) timeout = conf->timeout; } if (remote_num == 0 || remote_port == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) timeout = "10"; if (local_addr == NULL) local_addr = "0.0.0.0"; if (pid_flags) { USE_SYSLOG(argv[0]); demonize(pid_path); } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif // Setup keys LOGD("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd < 0) { FATAL("bind() error.."); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error."); } setnonblocking(listenfd); LOGD("server listening at port %s.", local_port); // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = malloc(sizeof(ss_addr_t) * remote_num); while (remote_num > 0) { int index = --remote_num; if (remote_addr[index].port == NULL) remote_addr[index].port = remote_port; listen_ctx.remote_addr[index] = remote_addr[index]; } listen_ctx.timeout = atoi(timeout); listen_ctx.fd = listenfd; listen_ctx.iface = iface; listen_ctx.method = m; struct ev_loop *loop = ev_default_loop(0); if (!loop) { FATAL("ev_loop error."); } ev_io_init (&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start (loop, &listen_ctx.io); // Setup UDP if (udprelay) { LOGD("udprelay enabled."); udprelay_init(local_addr, local_port, remote_addr[0].host, remote_addr[0].port, m, listen_ctx.timeout, iface); } // setuid if (user != NULL) run_as(user); ev_run (loop, 0); #ifdef __MINGW32__ winsock_cleanup(); #endif return 0; }
static void *status_thread (void *p) { THREAD_SIGINIT; /* (void)p; */ /* To inhibit "unused variable" warning */ if (!global.strict_suid) { if (!run_as(global.run_as)) { pdnsd_exit(); } } if (listen(stat_sock,5)==-1) { log_warn("Error: could not listen on socket: %s.\nStatus readback will be impossible",strerror(errno)); goto exit_thread; } for(;;) { struct sockaddr_un ra; socklen_t res=sizeof(ra); int rs; if ((rs=accept(stat_sock,(struct sockaddr *)&ra,&res))!=-1) { uint16_t cmd; DEBUG_MSG("Status socket query pending.\n"); if (read_short(rs,&cmd)) { /* Check magic number in command */ if((cmd & 0xff00) == CTL_CMDVERNR) { const char *errmsg; cmd &= 0xff; switch(cmd) { case CTL_STATS: { struct utsname nm; DEBUG_MSG("Received STATUS query.\n"); if(!print_succ(rs)) break; uname(&nm); if(fsprintf(rs,"pdnsd-%s running on %s.\n",VERSION,nm.nodename)<0 || report_cache_stat(rs)<0 || report_thread_stat(rs)<0 || report_conf_stat(rs)<0) { DEBUG_MSG("Error writing to control socket: %s\n" "Failed to send status report.\n",strerror(errno)); } } break; case CTL_SERVER: { char *label,*dnsaddr; int indx; uint16_t cmd2; DEBUG_MSG("Received SERVER command.\n"); if (read_allocstring(rs,&label,NULL)<=0) { print_serr(rs,"Error reading server label."); break; } if (!read_short(rs,&cmd2)) { print_serr(rs,"Missing up|down|retest."); goto free_label_break; } if(!read_allocstring(rs, &dnsaddr,NULL)) { print_serr(rs,"Error reading DNS addresses."); goto free_label_break; } /* Note by Paul Rombouts: We are about to access server configuration data. Now that the configuration can be changed during run time, we should be using locks before accessing server config data, even if it is read-only access. However, as long as this is the only thread that calls reload_config_file() it should be OK to read the server config without locks, but it is something to keep in mind. */ { char *endptr; indx=strtol(label,&endptr,0); if(!*endptr) { if (indx<0 || indx>=DA_NEL(servers)) { print_serr(rs,"Server index out of range."); goto free_dnsaddr_label_break; } } else { if (!strcmp(label, "all")) indx=-2; /* all servers */ else indx=-1; /* compare names */ } } if(cmd2==CTL_S_UP || cmd2==CTL_S_DOWN || cmd2==CTL_S_RETEST) { if(!dnsaddr) { if (indx==-1) { int i; for (i=0;i<DA_NEL(servers);++i) { char *servlabel=DA_INDEX(servers,i).label; if (servlabel && !strcmp(servlabel,label)) goto found_label; } print_serr(rs,"Bad server label."); goto free_dnsaddr_label_break; found_label:; } if(mark_servers(indx,(indx==-1)?label:NULL,(cmd2==CTL_S_RETEST)?-1:(cmd2==CTL_S_UP))==0) print_succ(rs); else print_serr(rs,"Could not start up or signal server status thread."); } else { /* Change server addresses */ if(indx==-2) { print_serr(rs,"Can't use label \"all\" to change server addresses."); goto free_dnsaddr_label_break; } if(indx==-1) { int i; for(i=0;i<DA_NEL(servers);++i) { char *servlabel=DA_INDEX(servers,i).label; if (servlabel && !strcmp(servlabel,label)) { if(indx!=-1) { print_serr(rs,"server label must be unique to change server addresses."); goto free_dnsaddr_label_break; } indx=i; } } if(indx==-1) { print_serr(rs,"Bad server label."); goto free_dnsaddr_label_break; } } { char *ipstr,*q=dnsaddr; addr_array ar=NULL; pdnsd_a addr; int err; for(;;) { for(;;) { if(!*q) goto change_servs; if(*q!=',' && !isspace(*q)) break; ++q; } ipstr=q; for(;;) { ++q; if(!*q) break; if(*q==',' || isspace(*q)) {*q++=0; break; } } if(!str2pdnsd_a(ipstr,&addr)) { print_serr(rs,"Bad server ip"); goto free_ar; } if(!(ar=DA_GROW1(ar))) { print_serr(rs,"Out of memory."); goto free_dnsaddr_label_break; } DA_LAST(ar)=addr; } change_servs: err=change_servers(indx,ar,(cmd2==CTL_S_RETEST)?-1:(cmd2==CTL_S_UP)); if(err==0) print_succ(rs); else print_serr(rs,err==ETIMEDOUT?"Timed out while trying to gain access to server data.": err==ENOMEM?"Out of memory.": "Could not start up or signal server status thread."); free_ar: da_free(ar); } } } else print_serr(rs,"Bad command."); free_dnsaddr_label_break: free(dnsaddr); free_label_break: free(label); } break; case CTL_RECORD: { uint16_t cmd2; unsigned char name[DNSNAMEBUFSIZE],buf[DNSNAMEBUFSIZE]; DEBUG_MSG("Received RECORD command.\n"); if (!read_short(rs,&cmd2)) goto incomplete_command; if (read_domain(rs, charp buf, sizeof(buf))<=0) goto incomplete_command; if ((errmsg=parsestr2rhn(buf,sizeof(buf),name))!=NULL) goto bad_domain_name; switch (cmd2) { case CTL_R_DELETE: del_cache(name); print_succ(rs); break; case CTL_R_INVAL: invalidate_record(name); print_succ(rs); break; default: print_serr(rs,"Bad command."); } } break; case CTL_SOURCE: { uint32_t ttl; char *fn; uint16_t servaliases,flags; unsigned char buf[DNSNAMEBUFSIZE],owner[DNSNAMEBUFSIZE]; DEBUG_MSG("Received SOURCE command.\n"); if (read_allocstring(rs,&fn,NULL)<=0) { print_serr(rs,"Bad filename name."); break; } if (read_domain(rs, charp buf, sizeof(buf))<=0 || !read_long(rs,&ttl) || !read_short(rs,&servaliases) || /* serve aliases */ !read_short(rs,&flags)) /* caching flags */ { print_serr(rs,"Malformed or incomplete command."); goto free_fn; } if ((errmsg=parsestr2rhn(buf,sizeof(buf),owner))!=NULL) { print_serr(rs,errmsg); goto free_fn; } if (ttl < 0) { print_serr(rs, "Bad TTL."); goto free_fn; } if(flags&DF_NEGATIVE) { print_serr(rs, "Bad cache flags."); goto free_fn; } { char *errmsg; if (read_hosts(fn,owner,ttl,flags,servaliases,&errmsg)) print_succ(rs); else { print_serr(rs,errmsg?:"Out of memory."); free(errmsg); } } free_fn: free(fn); } break; case CTL_ADD: { uint32_t ttl; unsigned sz; uint16_t tp,flags,nadr=0; unsigned char name[DNSNAMEBUFSIZE],buf[DNSNAMEBUFSIZE],dbuf[2+DNSNAMEBUFSIZE]; size_t adrbufsz=0; unsigned char *adrbuf=NULL; DEBUG_MSG("Received ADD command.\n"); if (!read_short(rs,&tp)) goto incomplete_command; if (read_domain(rs, charp buf, sizeof(buf))<=0) goto incomplete_command; if (!read_long(rs,&ttl)) goto incomplete_command; if (!read_short(rs,&flags)) /* caching flags */ goto incomplete_command; if ((errmsg=parsestr2rhn(buf,sizeof(buf),name))!=NULL) goto bad_domain_name; if (ttl < 0) goto bad_ttl; if(flags&DF_NEGATIVE) goto bad_flags; switch (tp) { case T_A: sz=sizeof(struct in_addr); #if ALLOW_LOCAL_AAAA goto read_adress_list; case T_AAAA: sz=sizeof(struct in6_addr); read_adress_list: #endif if (!read_short(rs,&nadr)) goto incomplete_command; if (!nadr) goto bad_arg; adrbufsz= nadr * (size_t)sz; adrbuf= malloc(adrbufsz); if(!adrbuf) goto out_of_memory; { size_t nread=0; while(nread<adrbufsz) { ssize_t m=read(rs,adrbuf+nread,adrbufsz-nread); if(m<=0) {free(adrbuf); goto bad_arg;} nread += m; } } break; case T_CNAME: case T_PTR: case T_NS: if (read_domain(rs, charp buf, sizeof(buf))<=0) goto incomplete_command; if ((errmsg=parsestr2rhn(buf,sizeof(buf),dbuf))!=NULL) goto bad_domain_name; sz=rhnlen(dbuf); break; case T_MX: if (read(rs,dbuf,2)!=2) goto bad_arg; if (read_domain(rs, charp buf, sizeof(buf))<=0) goto incomplete_command; if ((errmsg=parsestr2rhn(buf,sizeof(buf),dbuf+2))!=NULL) goto bad_domain_name; sz=rhnlen(dbuf+2)+2; break; default: goto bad_arg; } { dns_cent_t cent; if (!init_cent(¢, name, 0, 0, flags DBG1)) { free(adrbuf); goto out_of_memory; } if(adrbuf) { unsigned char *adrp; int i; for(adrp=adrbuf,i=0; i<nadr; adrp += sz,++i) { if (!add_cent_rr(¢,tp,ttl,0,CF_LOCAL,sz,adrp DBG1)) { free_cent(¢ DBG1); free(adrbuf); goto out_of_memory; } } free(adrbuf); } else if (!add_cent_rr(¢,tp,ttl,0,CF_LOCAL,sz,dbuf DBG1)) { free_cent(¢ DBG1); goto out_of_memory; } if(cent.qname[0]==1 && cent.qname[1]=='*') { /* Wild card record. Set the DF_WILD flag for the name with '*.' removed. */ if(!set_cent_flags(¢.qname[2],DF_WILD)) { print_serr(rs, "Before defining records for a name with a wildcard" " you must first define some records for the name" " with '*.' removed."); goto cleanup_cent; } } add_cache(¢); print_succ(rs); cleanup_cent: free_cent(¢ DBG1); } } break; case CTL_NEG: { uint32_t ttl; uint16_t tp; unsigned char name[DNSNAMEBUFSIZE],buf[DNSNAMEBUFSIZE]; DEBUG_MSG("Received NEG command.\n"); if (read_domain(rs, charp buf, sizeof(buf))<=0) goto incomplete_command; if (!read_short(rs,&tp)) goto incomplete_command; if (!read_long(rs,&ttl)) goto incomplete_command; if ((errmsg=parsestr2rhn(buf,sizeof(buf),name))!=NULL) { DEBUG_MSG("NEG: received bad domain name.\n"); goto bad_domain_name; } if (tp!=255 && PDNSD_NOT_CACHED_TYPE(tp)) { DEBUG_MSG("NEG: received bad record type.\n"); print_serr(rs,"Bad record type."); break; } if (ttl < 0) goto bad_ttl; { dns_cent_t cent; if (tp==255) { if (!init_cent(¢, name, ttl, 0, DF_LOCAL|DF_NEGATIVE DBG1)) goto out_of_memory; } else { if (!init_cent(¢, name, 0, 0, 0 DBG1)) goto out_of_memory; if (!add_cent_rrset_by_type(¢,tp,ttl,0,CF_LOCAL|CF_NEGATIVE DBG1)) { free_cent(¢ DBG1); goto out_of_memory; } } add_cache(¢); free_cent(¢ DBG1); } print_succ(rs); } break; case CTL_CONFIG: { char *fn,*errmsg; DEBUG_MSG("Received CONFIG command.\n"); if (!read_allocstring(rs,&fn,NULL)) { print_serr(rs,"Bad filename name."); break; } if (reload_config_file(fn,&errmsg)) print_succ(rs); else { print_serr(rs,errmsg?:"Out of memory."); free(errmsg); } free(fn); } break; case CTL_INCLUDE: { char *fn,*errmsg; DEBUG_MSG("Received INCLUDE command.\n"); if (read_allocstring(rs,&fn,NULL)<=0) { print_serr(rs,"Bad filename name."); break; } if (read_config_file(fn,NULL,NULL,0,&errmsg)) print_succ(rs); else { print_serr(rs,errmsg?:"Out of memory."); free(errmsg); } free(fn); } break; case CTL_EVAL: { char *str,*errmsg; DEBUG_MSG("Received EVAL command.\n"); if (!read_allocstring(rs,&str,NULL)) { print_serr(rs,"Bad input string."); break; } if (confparse(NULL,str,NULL,NULL,0,&errmsg)) print_succ(rs); else { print_serr(rs,errmsg?:"Out of memory."); free(errmsg); } free(str); } break; case CTL_EMPTY: { slist_array sla=NULL; char *names; unsigned len; DEBUG_MSG("Received EMPTY command.\n"); if (!read_allocstring(rs,&names,&len)) { print_serr(rs,"Bad arguments."); break; } if(names) { char *p=names, *last=names+len; while(p<last) { int tp; char *q; slist_t *sl; unsigned sz; unsigned char rhn[DNSNAMEBUFSIZE]; if(*p=='-') { tp=C_EXCLUDED; ++p; } else { tp=C_INCLUDED; if(*p=='+') ++p; } /* skip a possible leading dot. */ if(p+1<last && *p=='.' && *(p+1)) ++p; q=p; while(q<last && *q) ++q; if ((errmsg=parsestr2rhn(ucharp p,q-p,rhn))!=NULL) { DEBUG_MSG("EMPTY: received bad domain name: %s\n",p); print_serr(rs,errmsg); goto free_sla_names_break; } sz=rhnlen(rhn); if (!(sla=DA_GROW1_F(sla,free_slist_domain))) { print_serr(rs,"Out of memory."); goto free_names_break; } sl=&DA_LAST(sla); if (!(sl->domain=malloc(sz))) { print_serr(rs,"Out of memory."); goto free_sla_names_break; } memcpy(sl->domain,rhn,sz); sl->exact=0; sl->rule=tp; p = q+1; } } if(empty_cache(sla)) print_succ(rs); else print_serr(rs,"Could not lock the cache."); free_sla_names_break: free_slist_array(sla); free_names_break: free(names); } break; case CTL_DUMP: { int rv,exact=0; unsigned char *nm=NULL; char buf[DNSNAMEBUFSIZE]; unsigned char rhn[DNSNAMEBUFSIZE]; DEBUG_MSG("Received DUMP command.\n"); if (!(rv=read_domain(rs,buf,sizeof(buf)))) { print_serr(rs,"Bad domain name."); break; } if(rv>0) { int sz; exact=1; nm= ucharp buf; sz=sizeof(buf); if(buf[0]=='.' && buf[1]) { exact=0; ++nm; --sz; } if ((errmsg=parsestr2rhn(nm,sz,rhn))!=NULL) goto bad_domain_name; nm=rhn; } if(!print_succ(rs)) break; if((rv=dump_cache(rs,nm,exact))<0 || (!rv && fsprintf(rs,"Could not find %s%s in the cache.\n", exact?"":nm?"any entries matching ":"any entries", nm?buf:"")<0)) { DEBUG_MSG("Error writing to control socket: %s\n",strerror(errno)); } } break; incomplete_command: print_serr(rs,"Malformed or incomplete command."); break; bad_arg: print_serr(rs,"Bad arg."); break; bad_domain_name: print_serr(rs,errmsg); break; bad_ttl: print_serr(rs, "Bad TTL."); break; bad_flags: print_serr(rs, "Bad cache flags."); break; out_of_memory: print_serr(rs,"Out of memory."); break; default: print_serr(rs,"Unknown command."); } } else { DEBUG_MSG("Incorrect magic number in status-socket command code: %02x\n",cmd>>8); print_serr(rs,"Command code contains incompatible version number."); } } else {
int main(int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; char *iface = NULL; srand(time(NULL)); int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; int option_index = 0; static struct option long_options[] = { { "fast-open", no_argument, 0, 0 }, { "acl", required_argument, 0, 0 }, { 0, 0, 0, 0 } }; opterr = 0; USE_TTY(); #ifdef ANDROID while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uvVA", long_options, &option_index)) != -1) { #else while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uvA", long_options, &option_index)) != -1) { #endif switch (c) { case 0: if (option_index == 0) { fast_open = 1; } else if (option_index == 1) { LOGI("initialize acl..."); acl = !init_acl(optarg); } break; case 's': if (remote_num < MAX_REMOTE_NUM) { remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'i': iface = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; case 'u': mode = TCP_AND_UDP; break; case 'v': verbose = 1; break; case 'A': auth = 1; break; #ifdef ANDROID case 'V': vpn = 1; break; #endif } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) { remote_addr[i] = conf->remote_addr[i]; } } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (fast_open == 0) { fast_open = conf->fast_open; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif } if (remote_num == 0 || remote_port == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) { timeout = "60"; } if (local_addr == NULL) { local_addr = "127.0.0.1"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } if (fast_open == 1) { #ifdef TCP_FASTOPEN LOGI("using tcp fast open"); #else LOGE("tcp fast open is not supported by this environment"); #endif } if (auth) { LOGI("onetime authentication enabled"); } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif struct ev_signal sigint_watcher; struct ev_signal sigterm_watcher; ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); // Setup keys LOGI("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *) * remote_num); for (i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; } listen_ctx.timeout = atoi(timeout); listen_ctx.iface = iface; listen_ctx.method = m; struct ev_loop *loop = EV_DEFAULT; // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd < 0) { FATAL("bind() error"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); // Setup UDP if (mode != TCP_ONLY) { LOGI("udprelay enabled"); init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0], get_sockaddr_len(listen_ctx.remote_addr[0]), m, listen_ctx.timeout, iface); } LOGI("listening at %s:%s", local_addr, local_port); // setuid if (user != NULL) { run_as(user); } // Init connections cork_dllist_init(&connections); // Enter the loop ev_run(loop, 0); if (verbose) { LOGI("closed gracefully"); } // Clean up ev_io_stop(loop, &listen_ctx.io); free_connections(loop); if (mode != TCP_ONLY) { free_udprelay(); } for (i = 0; i < remote_num; i++) { free(listen_ctx.remote_addr[i]); } free(listen_ctx.remote_addr); #ifdef __MINGW32__ winsock_cleanup(); #endif ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); return 0; } #else int start_ss_local_server(profile_t profile) { srand(time(NULL)); char *remote_host = profile.remote_host; char *local_addr = profile.local_addr; char *method = profile.method; char *password = profile.password; char *log = profile.log; int remote_port = profile.remote_port; int local_port = profile.local_port; int timeout = profile.timeout; mode = profile.mode; fast_open = profile.fast_open; verbose = profile.verbose; char local_port_str[16]; char remote_port_str[16]; sprintf(local_port_str, "%d", local_port); sprintf(remote_port_str, "%d", remote_port); USE_LOGFILE(log); if (profile.acl != NULL) { acl = !init_acl(profile.acl); } if (local_addr == NULL) { local_addr = "127.0.0.1"; } #ifdef __MINGW32__ winsock_init(); #else // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif struct ev_signal sigint_watcher; struct ev_signal sigterm_watcher; ev_signal_init(&sigint_watcher, signal_cb, SIGINT); ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM); ev_signal_start(EV_DEFAULT, &sigint_watcher); ev_signal_start(EV_DEFAULT, &sigterm_watcher); // Setup keys LOGI("initialize ciphers... %s", method); int m = enc_init(password, method); struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(remote_host, remote_port_str, storage, 1) == -1) { return -1; } // Setup proxy context struct ev_loop *loop = EV_DEFAULT; struct listen_ctx listen_ctx; listen_ctx.remote_num = 1; listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *)); listen_ctx.remote_addr[0] = (struct sockaddr *)storage; listen_ctx.timeout = timeout; listen_ctx.method = m; listen_ctx.iface = NULL; // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port_str); if (listenfd < 0) { ERROR("bind()"); return -1; } if (listen(listenfd, SOMAXCONN) == -1) { ERROR("listen()"); return -1; } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); // Setup UDP if (mode != TCP_ONLY) { LOGI("udprelay enabled"); struct sockaddr *addr = (struct sockaddr *)storage; init_udprelay(local_addr, local_port_str, addr, get_sockaddr_len(addr), m, timeout, NULL); } LOGI("listening at %s:%s", local_addr, local_port_str); // Init connections cork_dllist_init(&connections); // Enter the loop ev_run(loop, 0); if (verbose) { LOGI("closed gracefully"); } // Clean up if (mode != TCP_ONLY) { free_udprelay(); } ev_io_stop(loop, &listen_ctx.io); free_connections(loop); close(listen_ctx.fd); free(listen_ctx.remote_addr); #ifdef __MINGW32__ winsock_cleanup(); #endif ev_signal_stop(EV_DEFAULT, &sigint_watcher); ev_signal_stop(EV_DEFAULT, &sigterm_watcher); // cannot reach here return 0; }
/* * Execute an individual uptest. Call with locks applied */ static int uptest (servparm_t *serv, int j) { int ret=0, count_running_ping=0; pdnsd_a *s_addr= PDNSD_A2_TO_A(&DA_INDEX(serv->atup_a,j).a); DEBUG_PDNSDA_MSG("performing uptest (type=%s) for %s\n",const_name(serv->uptest),PDNSDA2STR(s_addr)); /* Unlock the mutex because some of the tests may take a while. */ ++server_data_users; if((serv->uptest==C_PING || serv->uptest==C_QUERY) && pthread_equal(pthread_self(),servstat_thrid)) { /* Inform other threads that a ping is in progress. */ count_running_ping=1; ++server_status_ping; } pthread_mutex_unlock(&servers_lock); switch (serv->uptest) { case C_NONE: /* Don't change */ ret=DA_INDEX(serv->atup_a,j).is_up; break; case C_PING: ret=ping(is_inaddr_any(&serv->ping_a) ? s_addr : &serv->ping_a, serv->ping_timeout,PINGREPEAT)!=-1; break; case C_IF: case C_DEV: case C_DIALD: ret=if_up(serv->interface); #if (TARGET==TARGET_LINUX) if (ret!=0) { if(serv->uptest==C_DEV) ret=dev_up(serv->interface,serv->device); else if (serv->uptest==C_DIALD) ret=dev_up("diald",serv->device); } #endif break; case C_EXEC: { pid_t pid; if ((pid=fork())==-1) { DEBUG_MSG("Could not fork to perform exec uptest: %s\n",strerror(errno)); break; } else if (pid==0) { /* child */ /* * If we ran as setuid or setgid, do not inherit this to the * command. This is just a last guard. Running pdnsd as setuid() * or setgid() is a no-no. */ if (setgid(getgid()) == -1 || setuid(getuid()) == -1) { log_error("Could not reset uid or gid: %s",strerror(errno)); _exit(1); } /* Try to setuid() to a different user as specified. Good when you don't want the test command to run as root */ if (!run_as(serv->uptest_usr)) { _exit(1); } { struct rlimit rl; int i; /* * Mark all open fd's FD_CLOEXEC for paranoia reasons. */ if (getrlimit(RLIMIT_NOFILE, &rl) == -1) { log_error("getrlimit() failed: %s",strerror(errno)); _exit(1); } for (i = 0; i < rl.rlim_max; i++) { if (fcntl(i, F_SETFD, FD_CLOEXEC) == -1 && errno != EBADF) { log_error("fcntl(F_SETFD) failed: %s",strerror(errno)); _exit(1); } } } execl("/bin/sh", "uptest_sh","-c",serv->uptest_cmd,(char *)NULL); _exit(1); /* failed execl */ } else { /* parent */ int status; pid_t wpid = waitpid(pid,&status,0); if (wpid==pid) { if(WIFEXITED(status)) { int exitstatus=WEXITSTATUS(status); DEBUG_MSG("uptest command \"%s\" exited with status %d\n", serv->uptest_cmd, exitstatus); ret=(exitstatus==0); } #if DEBUG>0 else if(WIFSIGNALED(status)) { DEBUG_MSG("uptest command \"%s\" was terminated by signal %d\n", serv->uptest_cmd, WTERMSIG(status)); } else { DEBUG_MSG("status of uptest command \"%s\" is of unkown type (0x%x)\n", serv->uptest_cmd, status); } #endif } #if DEBUG>0 else if (wpid==-1) { DEBUG_MSG("Error while waiting for uptest command \"%s\" to terminate: " "waitpid for pid %d failed: %s\n", serv->uptest_cmd, pid, strerror(errno)); } else { DEBUG_MSG("Error while waiting for uptest command \"%s\" to terminate: " "waitpid returned %d, expected pid %d\n", serv->uptest_cmd, wpid, pid); } #endif } } break; case C_QUERY: ret=query_uptest(s_addr, serv->port, serv->timeout>=global.timeout?serv->timeout:global.timeout, PINGREPEAT); } /* end of switch */ pthread_mutex_lock(&servers_lock); if(count_running_ping) --server_status_ping; PDNSD_ASSERT(server_data_users>0, "server_data_users non-positive before attempt to decrement it"); if (--server_data_users==0) pthread_cond_broadcast(&server_data_cond); DEBUG_PDNSDA_MSG("result of uptest for %s: %s\n", PDNSDA2STR(s_addr), ret?"OK":"failed"); return ret; }
/* * This version of Berkeley's rwhod has been modified to use IP multicast * datagrams, under control of a new command-line option: * * rwhod -m causes rwhod to use IP multicast (instead of * broadcast or unicast) on all interfaces that have * the IFF_MULTICAST flag set in their "ifnet" structs * (excluding the loopback interface). The multicast * reports are sent with a time-to-live of 1, to prevent * forwarding beyond the directly-connected subnet(s). * * rwhod -m <ttl> causes rwhod to send IP multicast datagrams with a * time-to-live of <ttl>, via a SINGLE interface rather * than all interfaces. <ttl> must be between 0 and * MAX_MULTICAST_SCOPE, defined below. Note that "-m 1" * is different than "-m", in that "-m 1" specifies * transmission on one interface only. * * When "-m" is used without a <ttl> argument, the program accepts multicast * rwhod reports from all multicast-capable interfaces. If a <ttl> argument * is given, it accepts multicast reports from only one interface, the one * on which reports are sent (which may be controlled via the host's routing * table). Regardless of the "-m" option, the program accepts broadcast or * unicast reports from all interfaces. Thus, this program will hear the * reports of old, non-multicasting rwhods, but, if multicasting is used, * those old rwhods won't hear the reports generated by this program. * * -- Steve Deering, Stanford University, February 1989 */ int main(int argc, char *argv[]) { int on; char *cp; struct sockaddr_in soin; uid_t unpriv_uid; gid_t unpriv_gid; on = 1; if (getuid()) errx(1, "not super user"); run_as(&unpriv_uid, &unpriv_gid); argv++; argc--; while (argc > 0 && *argv[0] == '-') { if (strcmp(*argv, "-m") == 0) { if (argc > 1 && isdigit(*(argv + 1)[0])) { argv++; argc--; multicast_mode = SCOPED_MULTICAST; multicast_scope = atoi(*argv); if (multicast_scope > MAX_MULTICAST_SCOPE) { errx(1, "ttl must not exceed %u", MAX_MULTICAST_SCOPE); } } else { multicast_mode = PER_INTERFACE_MULTICAST; } } else if (strcmp(*argv, "-i") == 0) { insecure_mode = 1; } else if (strcmp(*argv, "-l") == 0) { quiet_mode = 1; } else if (strcmp(*argv, "-p") == 0) { iff_flag = 0; } else { usage(); } argv++; argc--; } if (argc > 0) usage(); #ifndef DEBUG daemon(1, 0); #endif (void) signal(SIGHUP, getboottime); openlog("rwhod", LOG_PID | LOG_NDELAY, LOG_DAEMON); sp = getservbyname("who", "udp"); if (sp == NULL) { syslog(LOG_ERR, "who/udp: unknown service"); exit(1); } if (chdir(_PATH_RWHODIR) < 0) { syslog(LOG_ERR, "%s: %m", _PATH_RWHODIR); exit(1); } /* * Establish host name as returned by system. */ if (gethostname(myname, sizeof(myname) - 1) < 0) { syslog(LOG_ERR, "gethostname: %m"); exit(1); } if ((cp = strchr(myname, '.')) != NULL) *cp = '\0'; strlcpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname)); getboottime(0); if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "socket: %m"); exit(1); } if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); exit(1); } memset(&soin, 0, sizeof(soin)); soin.sin_len = sizeof(soin); soin.sin_family = AF_INET; soin.sin_port = sp->s_port; if (bind(s, (struct sockaddr *)&soin, sizeof(soin)) < 0) { syslog(LOG_ERR, "bind: %m"); exit(1); } if (setgid(unpriv_gid) != 0) { syslog(LOG_ERR, "setgid: %m"); exit(1); } if (setgroups(1, &unpriv_gid) != 0) { /* XXX BOGUS groups[0] = egid */ syslog(LOG_ERR, "setgroups: %m"); exit(1); } if (setuid(unpriv_uid) != 0) { syslog(LOG_ERR, "setuid: %m"); exit(1); } if (!configure(s)) exit(1); if (!quiet_mode) { pid_child_receiver = pdfork(&fdp, 0); if (pid_child_receiver == 0) { receiver_process(); } else if (pid_child_receiver > 0) { sender_process(); } else if (pid_child_receiver == -1) { if (errno == ENOSYS) { syslog(LOG_ERR, "The pdfork(2) system call is not available - kernel too old."); } else { syslog(LOG_ERR, "pdfork: %m"); } exit(1); } } else { receiver_process(); } }
int main(int argc, char **argv) { int i, c; int pid_flags = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; opterr = 0; while ((c = getopt(argc, argv, "f:s:p:l:k:t:m:c:b:a:")) != -1) { switch (c) { case 's': if (remote_num < MAX_REMOTE_NUM) { remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if(argc == 1) { if(conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) { remote_addr[i] = conf->remote_addr[i]; } } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } } if (remote_num == 0 || remote_port == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (timeout == NULL) { timeout = "10"; } if (local_addr == NULL) { local_addr = "127.0.0.1"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); // Setup keys LOGI("initialize ciphers... %s", method); int m = enc_init(password, method); // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd < 0) { FATAL("bind() error"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); LOGI("listening at %s:%s", local_addr, local_port); // Setup proxy context struct listen_ctx listen_ctx; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *) * remote_num); for (int i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; } listen_ctx.timeout = atoi(timeout); listen_ctx.fd = listenfd; listen_ctx.method = m; struct ev_loop *loop = EV_DEFAULT; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); // setuid if (user != NULL) { run_as(user); } ev_run(loop, 0); return 0; }
int main(int argc, char **argv) { srand(time(NULL)); int i, c; int pid_flags = 0; int mptcp = 0; int mtu = 0; char *user = NULL; char *local_port = NULL; char *local_addr = NULL; char *password = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; char *conf_path = NULL; int remote_num = 0; ss_addr_t remote_addr[MAX_REMOTE_NUM]; char *remote_port = NULL; int option_index = 0; static struct option long_options[] = { { "mtu", required_argument, 0, 0 }, { "mptcp", no_argument, 0, 0 }, { "help", no_argument, 0, 0 }, { 0, 0, 0, 0 } }; opterr = 0; USE_TTY(); while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:b:a:n:huUvA6", long_options, &option_index)) != -1) { switch (c) { case 0: if (option_index == 0) { mtu = atoi(optarg); LOGI("set MTU to %d", mtu); } else if (option_index == 1) { mptcp = 1; LOGI("enable multipath TCP"); } else if (option_index == 2) { usage(); exit(EXIT_SUCCESS); } break; case 's': if (remote_num < MAX_REMOTE_NUM) { remote_addr[remote_num].host = optarg; remote_addr[remote_num++].port = NULL; } break; case 'p': remote_port = optarg; break; case 'l': local_port = optarg; break; case 'k': password = optarg; break; case 'f': pid_flags = 1; pid_path = optarg; break; case 't': timeout = optarg; break; case 'm': method = optarg; break; case 'c': conf_path = optarg; break; case 'b': local_addr = optarg; break; case 'a': user = optarg; break; #ifdef HAVE_SETRLIMIT case 'n': nofile = atoi(optarg); break; #endif case 'u': mode = TCP_AND_UDP; break; case 'U': mode = UDP_ONLY; break; case 'v': verbose = 1; break; case 'h': usage(); exit(EXIT_SUCCESS); case 'A': auth = 1; break; case '6': ipv6first = 1; break; case '?': // The option character is not recognized. LOGE("Unrecognized option: %s", optarg); opterr = 1; break; } } if (opterr) { usage(); exit(EXIT_FAILURE); } if (argc == 1) { if (conf_path == NULL) { conf_path = DEFAULT_CONF_PATH; } } if (conf_path != NULL) { jconf_t *conf = read_jconf(conf_path); if (remote_num == 0) { remote_num = conf->remote_num; for (i = 0; i < remote_num; i++) remote_addr[i] = conf->remote_addr[i]; } if (remote_port == NULL) { remote_port = conf->remote_port; } if (local_addr == NULL) { local_addr = conf->local_addr; } if (local_port == NULL) { local_port = conf->local_port; } if (password == NULL) { password = conf->password; } if (method == NULL) { method = conf->method; } if (timeout == NULL) { timeout = conf->timeout; } if (user == NULL) { user = conf->user; } if (auth == 0) { auth = conf->auth; } if (mtu == 0) { mtu = conf->mtu; } if (mptcp == 0) { mptcp = conf->mptcp; } #ifdef HAVE_SETRLIMIT if (nofile == 0) { nofile = conf->nofile; } #endif } if (remote_num == 0 || remote_port == NULL || local_port == NULL || password == NULL) { usage(); exit(EXIT_FAILURE); } if (method == NULL) { method = "rc4-md5"; } if (timeout == NULL) { timeout = "600"; } #ifdef HAVE_SETRLIMIT /* * no need to check the return value here since we will show * the user an error message if setrlimit(2) fails */ if (nofile > 1024) { if (verbose) { LOGI("setting NOFILE to %d", nofile); } set_nofile(nofile); } #endif if (local_addr == NULL) { local_addr = "127.0.0.1"; } if (pid_flags) { USE_SYSLOG(argv[0]); daemonize(pid_path); } if (ipv6first) { LOGI("resolving hostname to IPv6 address first"); } if (auth) { LOGI("onetime authentication enabled"); } // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); signal(SIGINT, signal_cb); signal(SIGTERM, signal_cb); // Setup keys LOGI("initializing ciphers... %s", method); int m = enc_init(password, method); // Setup proxy context listen_ctx_t listen_ctx; listen_ctx.remote_num = remote_num; listen_ctx.remote_addr = ss_malloc(sizeof(struct sockaddr *) * remote_num); for (int i = 0; i < remote_num; i++) { char *host = remote_addr[i].host; char *port = remote_addr[i].port == NULL ? remote_port : remote_addr[i].port; struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage)); memset(storage, 0, sizeof(struct sockaddr_storage)); if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) { FATAL("failed to resolve the provided hostname"); } listen_ctx.remote_addr[i] = (struct sockaddr *)storage; } listen_ctx.timeout = atoi(timeout); listen_ctx.method = m; listen_ctx.mptcp = mptcp; struct ev_loop *loop = EV_DEFAULT; if (mode != UDP_ONLY) { // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port); if (listenfd == -1) { FATAL("bind() error"); } if (listen(listenfd, SOMAXCONN) == -1) { FATAL("listen() error"); } setnonblocking(listenfd); listen_ctx.fd = listenfd; ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start(loop, &listen_ctx.io); } // Setup UDP if (mode != TCP_ONLY) { LOGI("UDP relay enabled"); init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0], get_sockaddr_len(listen_ctx.remote_addr[0]), mtu, m, auth, listen_ctx.timeout, NULL); } if (mode == UDP_ONLY) { LOGI("TCP relay disabled"); } LOGI("listening at %s:%s", local_addr, local_port); // setuid if (user != NULL && ! run_as(user)) { FATAL("failed to switch user"); } if (geteuid() == 0){ LOGI("running from root user"); } ev_run(loop, 0); return 0; }
int main(int argc, char *argv[]) { struct pollfd pfd[1]; char *ep, *cp; int on = 1; int send_time = 180; /* Default time, 180 seconds (3 minutes) */ struct sockaddr_in m_sin; uid_t unpriv_uid; gid_t unpriv_gid; long tmp; time_t delta = 0; struct timeval next, now; if (getuid()) errx(1, "not super user"); run_as(&unpriv_uid, &unpriv_gid); argv++; argc--; while (argc > 0 && *argv[0] == '-') { if (strcmp(*argv, "-m") == 0) { if (argc > 1 && *(argv + 1)[0] != '-') { /* Argument has been given */ argv++, argc--; multicast_mode = SCOPED_MULTICAST; tmp = strtol(*argv, &ep, 10); if (*ep != '\0' || tmp < INT_MIN || tmp > INT_MAX) errx(1, "invalid ttl: %s", *argv); multicast_scope = (int)tmp; if (multicast_scope > MAX_MULTICAST_SCOPE) errx(1, "ttl must not exceed %u", MAX_MULTICAST_SCOPE); } else multicast_mode = PER_INTERFACE_MULTICAST; } else if (strcmp(*argv, "-g") == 0) { if (argc > 1 && *(argv + 1)[0] != '-') { argv++, argc--; send_time = (int)strtol(*argv, &ep, 10); if (send_time <= 0) errx(1, "time must be greater than 0"); if (ep[0] != '\0') { if (ep[1] != '\0') errx(1, "invalid argument: %s", *argv); if (*ep == 'M' || *ep == 'm') { /* Time in minutes. */ send_time *= 60; } else errx(1, "invalid argument: %s", *argv); } if (send_time > 180) errx(1, "cannot be greater than 180 seconds (3 minutes)"); } else errx(1, "missing argument"); } else if (strcmp(*argv, "-i") == 0) insecure_mode = 1; else if (strcmp(*argv, "-l") == 0) quiet_mode = 1; else if (strcmp(*argv, "-p") == 0) iff_flag = 0; else usage(); argv++, argc--; } if (argc > 0) usage(); #ifndef DEBUG struct pidfh *pfh = NULL; pfh = pidfile_open(NULL, 600, NULL); daemon(1, 0); pidfile_write(pfh); #endif signal(SIGHUP, hup); openlog("rwhod", LOG_PID, LOG_DAEMON); sp = getservbyname("who", "udp"); if (sp == NULL) quit("udp/who: unknown service", WITHOUT_ERRNO); if (chdir(_PATH_RWHODIR) < 0) quit(_PATH_RWHODIR, WITH_ERRNO); /* * Establish host name as returned by system. */ if (gethostname(myname, sizeof(myname)) < 0) quit("gethostname", WITH_ERRNO); if ((cp = strchr(myname, '.')) != NULL) *cp = '\0'; strlcpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname)); utmpf = open(_PATH_UTMP, O_RDONLY|O_CREAT, 0644); if (utmpf < 0) quit(_PATH_UTMP, WITH_ERRNO); getboottime(); if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) quit("socket", WITH_ERRNO); if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) quit("setsockopt SO_BROADCAST", WITH_ERRNO); memset(&m_sin, 0, sizeof(m_sin)); m_sin.sin_len = sizeof(m_sin); m_sin.sin_family = AF_INET; m_sin.sin_port = sp->s_port; if (bind(s, (struct sockaddr *)&m_sin, sizeof(m_sin)) < 0) quit("bind", WITH_ERRNO); setgid(unpriv_gid); setgroups(1, &unpriv_gid); /* XXX BOGUS groups[0] = egid */ setuid(unpriv_uid); if (!configure(s)) exit(1); if (!quiet_mode) { send_host_information(); delta = send_time; gettimeofday(&now, NULL); timeadd(&now, delta, &next); } pfd[0].fd = s; pfd[0].events = POLLIN; for (;;) { int n; n = poll(pfd, 1, 1000); if (onsighup) { onsighup = 0; getboottime(); } if (n == 1) handleread(s); if (!quiet_mode) { gettimeofday(&now, NULL); if (now.tv_sec > next.tv_sec) { send_host_information(); timeadd(&now, delta, &next); } } } }