示例#1
0
文件: runas.c 项目: lttng/lttng-tools
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;
}
示例#2
0
文件: runas.c 项目: lttng/lttng-tools
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;
}
示例#3
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);
}
示例#4
0
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);
}
示例#5
0
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");
}
示例#6
0
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);
}
示例#7
0
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);
}
示例#8
0
文件: runas.c 项目: lttng/lttng-tools
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;
}
示例#9
0
文件: runas.c 项目: lttng/lttng-tools
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;
}
示例#10
0
文件: runas.c 项目: lttng/lttng-tools
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;
}
示例#11
0
文件: runas.c 项目: lttng/lttng-tools
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;
}
示例#12
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;
}
示例#13
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;
}
示例#14
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;
}
示例#15
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;
}
示例#16
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;
}
示例#17
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;
}
示例#18
0
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;
}
示例#19
0
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);
	}
}
示例#20
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;

    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;
}
示例#21
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;
}
示例#22
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(&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(&cent,tp,ttl,0,CF_LOCAL,sz,adrp  DBG1)) {
									free_cent(&cent  DBG1);
									free(adrbuf);
									goto out_of_memory;
								}
							}
							free(adrbuf);
						}
						else if (!add_cent_rr(&cent,tp,ttl,0,CF_LOCAL,sz,dbuf  DBG1)) {
							free_cent(&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(&cent.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(&cent);
						print_succ(rs);
					cleanup_cent:
						free_cent(&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(&cent, name, ttl, 0, DF_LOCAL|DF_NEGATIVE  DBG1))
								goto out_of_memory;
						} else {
							if (!init_cent(&cent, name, 0, 0, 0  DBG1))
								goto out_of_memory;
							if (!add_cent_rrset_by_type(&cent,tp,ttl,0,CF_LOCAL|CF_NEGATIVE  DBG1)) {
								free_cent(&cent  DBG1);
								goto out_of_memory;
							}
						}
						add_cache(&cent);
						free_cent(&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 {
示例#23
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;

    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;
}
示例#24
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;
}
示例#25
0
/*
 * 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();
	}
}
示例#26
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:")) != -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;
}
示例#27
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;
}
示例#28
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);
			}
		}
	}
}