Beispiel #1
0
static xmlNodePtr _dump_stats_to_doc (xmlNodePtr root, const char *show_mount, int hidden) {
    avl_node *avlnode;
    xmlNodePtr ret = NULL;
    ice_config_t *config;

    thread_mutex_lock(&_stats_mutex);
    /* general stats first */
    avlnode = avl_get_first(_stats.global_tree);

    while (avlnode) {
        stats_node_t *stat = avlnode->key;
        if (stat->hidden <=  hidden)
            xmlNewTextChild (root, NULL, XMLSTR(stat->name), XMLSTR(stat->value));
        avlnode = avl_get_next (avlnode);
    }
    /* now per mount stats */
    avlnode = avl_get_first(_stats.source_tree);
    config = config_get_config();
    __add_authstack(config->authstack, root);
    config_release_config();

    while (avlnode) {
        stats_source_t *source = (stats_source_t *)avlnode->key;

        if (source->hidden <= hidden &&
                (show_mount == NULL || strcmp (show_mount, source->source) == 0))
        {
            xmlNodePtr metadata, history;
            source_t *source_real;
            mount_proxy *mountproxy;
            int i;

            avl_node *avlnode2 = avl_get_first (source->stats_tree);
            xmlNodePtr xmlnode = xmlNewTextChild (root, NULL, XMLSTR("source"), NULL);

            xmlSetProp (xmlnode, XMLSTR("mount"), XMLSTR(source->source));
            if (ret == NULL)
                ret = xmlnode;
            while (avlnode2)
            {
                stats_node_t *stat = avlnode2->key;
                xmlNewTextChild (xmlnode, NULL, XMLSTR(stat->name), XMLSTR(stat->value));
                avlnode2 = avl_get_next (avlnode2);
            }


            avl_tree_rlock(global.source_tree);
            source_real = source_find_mount_raw(source->source);
            history = playlist_render_xspf(source_real->history);
            if (history)
                xmlAddChild(xmlnode, history);
            metadata = xmlNewTextChild(xmlnode, NULL, XMLSTR("metadata"), NULL);
            if (source_real->format) {
                for (i = 0; i < source_real->format->vc.comments; i++)
                    __add_metadata(metadata, source_real->format->vc.user_comments[i]);
            }
            avl_tree_unlock(global.source_tree);

            config = config_get_config();
            mountproxy = config_find_mount(config, source->source, MOUNT_TYPE_NORMAL);
            __add_authstack(mountproxy->authstack, xmlnode);
            config_release_config();
        }
        avlnode = avl_get_next (avlnode);
    }
    thread_mutex_unlock(&_stats_mutex);
    return ret;
}
Beispiel #2
0
        /*
         * @return A string containing human-readable status text. MUST BE free()d by caller
         */
char *
get_status_text()
{
    pstr_t *pstr = pstr_new();
    s_config *config;
    t_auth_serv *auth_server;
    t_client *sublist, *current;
    int count;
    time_t uptime = 0;
    unsigned int days = 0, hours = 0, minutes = 0, seconds = 0;
    t_trusted_mac *p;
	t_offline_client *oc_list;

    pstr_cat(pstr, "WiFiDog status\n\n");

    uptime = time(NULL) - started_time;
    days = (unsigned int)uptime / (24 * 60 * 60);
    uptime -= days * (24 * 60 * 60);
    hours = (unsigned int)uptime / (60 * 60);
    uptime -= hours * (60 * 60);
    minutes = (unsigned int)uptime / 60;
    uptime -= minutes * 60;
    seconds = (unsigned int)uptime;

    pstr_cat(pstr, "Version: " VERSION "\n");
    pstr_append_sprintf(pstr, "Uptime: %ud %uh %um %us\n", days, hours, minutes, seconds);
    pstr_cat(pstr, "Has been restarted: ");

    if (restart_orig_pid) {
        pstr_append_sprintf(pstr, "yes (from PID %d)\n", restart_orig_pid);
    } else {
        pstr_cat(pstr, "no\n");
    }

    pstr_append_sprintf(pstr, "Internet Connectivity: %s\n", (is_online()? "yes" : "no"));
    pstr_append_sprintf(pstr, "Auth server reachable: %s\n", (is_auth_online()? "yes" : "no"));
    pstr_append_sprintf(pstr, "Clients served this session: %lu\n\n", served_this_session);

    LOCK_CLIENT_LIST();

    count = client_list_dup(&sublist);

    UNLOCK_CLIENT_LIST();

    current = sublist;

    pstr_append_sprintf(pstr, "%d clients " "connected.\n", count);

    count = 1;
    while (current != NULL) {
        pstr_append_sprintf(pstr, "\nClient %d status [%d]\n", count, current->is_online);
        pstr_append_sprintf(pstr, "  IP: %s MAC: %s\n", current->ip, current->mac);
        pstr_append_sprintf(pstr, "  Token: %s\n", current->token);
        pstr_append_sprintf(pstr, "  First Login: %lld\n", (long long)current->first_login);
        pstr_append_sprintf(pstr, "  Name: %s\n", current->name != NULL?current->name:"null");
        pstr_append_sprintf(pstr, "  Downloaded: %llu\n  Uploaded: %llu\n", current->counters.incoming,
                            current->counters.outgoing);
        count++;
        current = current->next;
    }

    client_list_destroy(sublist);

	LOCK_OFFLINE_CLIENT_LIST();
    pstr_append_sprintf(pstr, "%d clients " "unconnected.\n", offline_client_number());
	oc_list = client_get_first_offline_client();
	while(oc_list != NULL) {	
        pstr_append_sprintf(pstr, "  IP: %s MAC: %s Last Login: %lld Hit Counts: %d Client Type: %d Temp Passed: %d\n", 
			oc_list->ip, oc_list->mac, (long long)oc_list->last_login, 
			oc_list->hit_counts, oc_list->client_type, oc_list->temp_passed);
		oc_list = oc_list->next;
	}
	UNLOCK_OFFLINE_CLIENT_LIST();

    config = config_get_config();

    LOCK_CONFIG();

    if (config->trustedmaclist != NULL) {
        pstr_cat(pstr, "\nTrusted MAC addresses:\n");

        for (p = config->trustedmaclist; p != NULL; p = p->next) {
            pstr_append_sprintf(pstr, "  %s\n", p->mac);
        }
    }

    pstr_cat(pstr, "\nAuthentication servers:\n");


    for (auth_server = config->auth_servers; auth_server != NULL; auth_server = auth_server->next) {
        pstr_append_sprintf(pstr, "  Host: %s (%s)\n", auth_server->authserv_hostname, auth_server->last_ip);
    }

    UNLOCK_CONFIG();

    return pstr_to_string(pstr);
}
Beispiel #3
0
static void *start_relay_stream (void *arg)
{
    client_t *client = arg;
    relay_server *relay;
    source_t *src;
    int failed = 1, sources;

    global_lock();
    sources = ++global.sources;
    stats_event_args (NULL, "sources", "%d", global.sources);
    global_unlock();
    /* set the start time, because we want to decrease the sources on all failures */
    client->connection.con_time = time (NULL);
    do
    {
        ice_config_t *config = config_get_config();
        mount_proxy *mountinfo;

        relay = client->shared_data;
        src = relay->source;

        thread_rwlock_wlock (&src->lock);
        src->flags |= SOURCE_PAUSE_LISTENERS;
        if (sources > config->source_limit)
        {
            config_release_config();
            WARN1 ("starting relayed mountpoint \"%s\" requires a higher sources limit", relay->localmount);
            break;
        }
        config_release_config();
        INFO1("Starting relayed source at mountpoint \"%s\"", relay->localmount);

        if (open_relay (relay) < 0)
            break;
        if (connection_complete_source (src) < 0)
        {
            WARN1 ("Failed to complete initialisation on %s", relay->localmount);
            break;
        }
        stats_event_inc (NULL, "source_relay_connections");
        source_init (src);
        config = config_get_config();
        mountinfo = config_find_mount (config, src->mount);
        source_update_settings (config, src, mountinfo);
        INFO1 ("source %s is ready to start", src->mount);
        config_release_config();
        failed = 0;
    } while (0);

    client->ops = &relay_client_ops;
    client->schedule_ms = timing_get_time();

    if (failed)
    {
        /* failed to start any connection, better clean up and reset */
        if (relay->on_demand == 0)
        {
            yp_remove (relay->localmount);
            src->yp_public = -1;
        }
        relay->in_use = NULL;
        INFO2 ("listener count remaining on %s is %d", src->mount, src->listeners);
        src->flags &= ~(SOURCE_PAUSE_LISTENERS|SOURCE_RUNNING);
    }
    thread_rwlock_unlock (&src->lock);

    thread_spin_lock (&relay_start_lock);
    relays_connecting--;
    thread_spin_unlock (&relay_start_lock);

    client->flags |= CLIENT_ACTIVE;
    worker_wakeup (client->worker);
    return NULL;
}
Beispiel #4
0
void connection_accept_loop (void)
{
    connection_t *con;
    ice_config_t *config;
    int duration = 300;

    config = config_get_config ();
    get_ssl_certificate (config);
    config_release_config ();

    while (global.running == ICE_RUNNING)
    {
        con = _accept_connection (duration);

        if (con)
        {
            client_queue_t *node;
            ice_config_t *config;
            client_t *client = NULL;
            listener_t *listener;

            global_lock();
            if (client_create (&client, con, NULL) < 0)
            {
                global_unlock();
                client_send_403 (client, "Icecast connection limit reached");
                /* don't be too eager as this is an imposed hard limit */
                thread_sleep (400000);
                continue;
            }

            /* setup client for reading incoming http */
            client->refbuf->data [PER_CLIENT_REFBUF_SIZE-1] = '\000';

            if (sock_set_blocking (client->con->sock, 0) || sock_set_nodelay (client->con->sock))
            {
                global_unlock();
                WARN0 ("failed to set tcp options on client connection, dropping");
                client_destroy (client);
                continue;
            }

            node = calloc (1, sizeof (client_queue_t));
            if (node == NULL)
            {
                global_unlock();
                client_destroy (client);
                continue;
            }
            node->client = client;

            config = config_get_config();
            listener = config_get_listen_sock (config, client->con);

            if (listener)
            {
                if (listener->shoutcast_compat)
                    node->shoutcast = 1;
                if (listener->ssl && ssl_ok)
                    connection_uses_ssl (client->con);
                if (listener->shoutcast_mount)
                    node->shoutcast_mount = strdup (listener->shoutcast_mount);
            }
            global_unlock();
            config_release_config();

            _add_request_queue (node);
            stats_event_inc (NULL, "connections");
            duration = 5;
        }
        else
        {
            if (_req_queue == NULL)
                duration = 300; /* use longer timeouts when nothing waiting */
        }
        process_request_queue ();
    }

    /* Give all the other threads notification to shut down */
    thread_cond_broadcast(&global.shutdown_cond);

    /* wait for all the sources to shutdown */
    thread_rwlock_wlock(&_source_shutdown_rwlock);
    thread_rwlock_unlock(&_source_shutdown_rwlock);
}
Beispiel #5
0
static auth_result url_remove_listener (auth_client *auth_user)
{
    client_t *client = auth_user->client;
    auth_t *auth = client->auth;
    auth_url *url = auth->state;
    time_t duration = time(NULL) - client->con->con_time;
    char *username, *password, *mount, *server;
    const char *mountreq;
    ice_config_t *config;
    int port;
    char *userpwd = NULL, post [4096];
    const char *agent;
    char *user_agent, *ipaddr;

    if (url->removeurl == NULL)
        return AUTH_OK;

    config = config_get_config ();
    server = util_url_escape (config->hostname);
    port = config->port;
    config_release_config ();

    agent = httpp_getvar (client->parser, "user-agent");
    if (agent)
        user_agent = util_url_escape (agent);
    else
        user_agent = strdup ("-");

    if (client->username)
        username = util_url_escape (client->username);
    else
        username = strdup ("");

    if (client->password)
        password = util_url_escape (client->password);
    else
        password = strdup ("");

    /* get the full uri (with query params if available) */
    mountreq = httpp_getvar (client->parser, HTTPP_VAR_RAWURI);
    if (mountreq == NULL)
        mountreq = httpp_getvar (client->parser, HTTPP_VAR_URI);
    mount = util_url_escape (mountreq);
    ipaddr = util_url_escape (client->con->ip);

    snprintf (post, sizeof (post),
            "action=listener_remove&server=%s&port=%d&client=%lu&mount=%s"
            "&user=%s&pass=%s&duration=%lu&ip=%s&agent=%s",
            server, port, client->con->id, mount, username,
            password, (long unsigned)duration, ipaddr, user_agent);
    free (server);
    free (mount);
    free (username);
    free (password);
    free (ipaddr);
    free (user_agent);

    if (strchr (url->removeurl, '@') == NULL)
    {
        if (url->userpwd)
            curl_easy_setopt (url->handle, CURLOPT_USERPWD, url->userpwd);
        else
        {
            /* auth'd requests may not have a user/pass, but may use query args */
            if (client->username && client->password)
            {
                size_t len = strlen (client->username) + strlen (client->password) + 2;
                userpwd = malloc (len);
                snprintf (userpwd, len, "%s:%s", client->username, client->password);
                curl_easy_setopt (url->handle, CURLOPT_USERPWD, userpwd);
            }
            else
                curl_easy_setopt (url->handle, CURLOPT_USERPWD, "");
        }
    }
    else
    {
        /* url has user/pass but libcurl may need to clear any existing settings */
        curl_easy_setopt (url->handle, CURLOPT_USERPWD, "");
    }
    curl_easy_setopt (url->handle, CURLOPT_URL, url->removeurl);
    curl_easy_setopt (url->handle, CURLOPT_POSTFIELDS, post);
    curl_easy_setopt (url->handle, CURLOPT_WRITEHEADER, auth_user);

    if (curl_easy_perform (url->handle))
        WARN2 ("auth to server %s failed with %s", url->removeurl, url->errormsg);

    free (userpwd);

    return AUTH_OK;
}
/* Called when activating a source. Verifies that the source count is not
 * exceeded and applies any initial parameters.
 */
int connection_complete_source (source_t *source, int response)
{
    ice_config_t *config = config_get_config();

    global_lock ();
    DEBUG1 ("sources count is %d", global.sources);

    if (global.sources < config->source_limit)
    {
        char *contenttype;
        mount_proxy *mountinfo;
        format_type_t format_type;

        /* setup format handler */
        contenttype = httpp_getvar (source->parser, "content-type");
        if (contenttype != NULL)
        {
            format_type = format_get_type (contenttype);

            if (format_type == FORMAT_ERROR)
            {
                global_unlock();
                config_release_config();
                if (response)
                {
                    client_send_404 (source->client, "Content-type not supported");
                    source->client = NULL;
                }
                WARN1("Content-type \"%s\" not supported, dropping source", contenttype);
                return -1;
            }
        }
        else
        {
            WARN0("No content-type header, falling back to backwards compatibility mode "
                    "for icecast 1.x relays. Assuming content is mp3.");
            format_type = FORMAT_TYPE_GENERIC;
        }

        if (format_get_plugin (format_type, source) < 0)
        {
            global_unlock();
            config_release_config();
            if (response)
            {
                client_send_404 (source->client, "internal format allocation problem");
                source->client = NULL;
            }
            WARN1 ("plugin format failed for \"%s\"", source->mount);
            return -1;
        }

        global.sources++;
        stats_event_args (NULL, "sources", "%d", global.sources);
        global_unlock();

        source->running = 1;
        mountinfo = config_find_mount (config, source->mount);
        if (mountinfo == NULL)
            source_update_settings (config, source, mountinfo);
        source_recheck_mounts ();
        config_release_config();

        source->shutdown_rwlock = &_source_shutdown_rwlock;
        DEBUG0 ("source is ready to start");

        return 0;
    }
    WARN1("Request to add source when maximum source limit "
            "reached %d", global.sources);

    global_unlock();
    config_release_config();

    if (response)
    {
        client_send_404 (source->client, "too many sources connected");
        source->client = NULL;
    }

    return -1;
}
Beispiel #7
0
static void _handle_shoutcast_compatible (client_queue_t *node)
{
    char *http_compliant;
    int http_compliant_len = 0;
    http_parser_t *parser;
    ice_config_t *config = config_get_config ();
    char *shoutcast_mount;
    client_t *client = node->client;

    if (node->shoutcast_mount)
        shoutcast_mount = node->shoutcast_mount;
    else
        shoutcast_mount = config->shoutcast_mount;

    if (node->shoutcast == 1)
    {
        char *source_password, *ptr, *headers;
        mount_proxy *mountinfo = config_find_mount (config, shoutcast_mount, MOUNT_TYPE_NORMAL);

        if (mountinfo && mountinfo->password)
            source_password = strdup (mountinfo->password);
        else
        {
            if (config->source_password) 
                source_password = strdup (config->source_password);
            else
                source_password = NULL;
        }
        config_release_config();

        /* Get rid of trailing \r\n or \n after password */
        ptr = strstr (client->refbuf->data, "\r\r\n");
        if (ptr)
            headers = ptr+3;
        else
        {
            ptr = strstr (client->refbuf->data, "\r\n");
            if (ptr)
                headers = ptr+2;
            else
            {
                ptr = strstr (client->refbuf->data, "\n");
                if (ptr)
                    headers = ptr+1;
            }
        }

        if (ptr == NULL)
        {
            client_destroy (client);
            free (source_password);
            free (node->shoutcast_mount);
            free (node);
            return;
        }
        *ptr = '\0';

        if (source_password && strcmp (client->refbuf->data, source_password) == 0)
        {
            client->respcode = 200;
            /* send this non-blocking but if there is only a partial write
             * then leave to header timeout */
            sock_write (client->con->sock, "OK2\r\nicy-caps:11\r\n\r\n");
            node->offset -= (headers - client->refbuf->data);
            memmove (client->refbuf->data, headers, node->offset+1);
            node->shoutcast = 2;
            /* we've checked the password, now send it back for reading headers */
            _add_request_queue (node);
            free (source_password);
            return;
        }
        else
            INFO1 ("password does not match \"%s\"", client->refbuf->data);
        client_destroy (client);
        free (source_password);
        free (node->shoutcast_mount);
        free (node);
        return;
    }
    /* actually make a copy as we are dropping the config lock */
    shoutcast_mount = strdup (shoutcast_mount);
    config_release_config();
    /* Here we create a valid HTTP request based of the information
       that was passed in via the non-HTTP style protocol above. This
       means we can use some of our existing code to handle this case */
    http_compliant_len = 20 + strlen (shoutcast_mount) + node->offset;
    http_compliant = (char *)calloc(1, http_compliant_len);
    snprintf (http_compliant, http_compliant_len,
            "SOURCE %s HTTP/1.0\r\n%s", shoutcast_mount, client->refbuf->data);
    parser = httpp_create_parser();
    httpp_initialize(parser, NULL);
    if (httpp_parse (parser, http_compliant, strlen(http_compliant)))
    {
        /* we may have more than just headers, so prepare for it */
        if (node->stream_offset == node->offset)
            client->refbuf->len = 0;
        else
        {
            char *ptr = client->refbuf->data;
            client->refbuf->len = node->offset - node->stream_offset;
            memmove (ptr, ptr + node->stream_offset, client->refbuf->len);
        }
        client->parser = parser;
        source_startup (client, shoutcast_mount, SHOUTCAST_SOURCE_AUTH);
    }
    else {
        httpp_destroy (parser);
        client_destroy (client);
    }
    free (http_compliant);
    free (shoutcast_mount);
    free (node->shoutcast_mount);
    free (node);
    return;
}
Beispiel #8
0
int fserve_setup_client_fb (client_t *client, fbinfo *finfo)
{
    fh_node *fh = &no_file;
    int ret = 0;

    if (finfo)
    {
        mount_proxy *minfo;
        if (finfo->flags & FS_FALLBACK && finfo->limit == 0)
            return -1;
        avl_tree_wlock (fh_cache);
        fh = find_fh (finfo);
        minfo = config_find_mount (config_get_config(), finfo->mount);
        if (fh)
        {
            thread_mutex_lock (&fh->lock);
            avl_tree_unlock (fh_cache);
            client->shared_data = NULL;
            if (minfo)
            {
                if (minfo->max_listeners >= 0 && fh->refcount > minfo->max_listeners)
                {
                    thread_mutex_unlock (&fh->lock);
                    config_release_config();
                    return client_send_403redirect (client, finfo->mount, "max listeners reached");
                }
                if (check_duplicate_logins (finfo->mount, fh->clients, client, minfo->auth) == 0)
                {
                    thread_mutex_unlock (&fh->lock);
                    config_release_config();
                    return client_send_403 (client, "Account already in use");
                }
            }
            config_release_config();
        }
        else
        {
            if (minfo && minfo->max_listeners == 0)
            {
                avl_tree_unlock (fh_cache);
                config_release_config();
                client->shared_data = NULL;
                return client_send_403redirect (client, finfo->mount, "max listeners reached");
            }
            config_release_config();
            fh = open_fh (finfo);
            if (fh == NULL)
                return client_send_404 (client, NULL);
            if (fh->finfo.limit)
                DEBUG2 ("request for throttled file %s (bitrate %d)", fh->finfo.mount, fh->finfo.limit*8);
        }
        if (fh->finfo.limit)
        {
            client->timer_start = client->worker->current_time.tv_sec;
            if (client->connection.sent_bytes == 0)
                client->timer_start -= 2;
            client->counter = 0;
            global_reduce_bitrate_sampling (global.out_bitrate);
        }
    }
    else
    {
        if (client->mount && (client->flags & CLIENT_AUTHENTICATED) && (client->respcode >= 300 || client->respcode < 200))
        {
            fh = calloc (1, sizeof (no_file));
            fh->finfo.mount = strdup (client->mount);
            fh->finfo.flags |= FS_DELETE;
            fh->refcount = 1;
            fh->f = SOCK_ERROR;
            thread_mutex_create (&fh->lock);
        }
        thread_mutex_lock (&fh->lock);
    }
    client->mount = fh->finfo.mount;
    if (fh->finfo.type == FORMAT_TYPE_UNDEFINED)
    {
        if (client->respcode == 0)
        {
            client->refbuf->len = 0;
            ret = format_general_headers (fh->format, client);
        }
    }
    else
    {
        if (fh->format->create_client_data && client->format_data == NULL)
            ret = fh->format->create_client_data (fh->format, client);
        if (fh->format->write_buf_to_client)
            client->check_buffer = fh->format->write_buf_to_client;
    }
    if (ret < 0)
    {
        thread_mutex_unlock (&fh->lock);
        return client_send_416 (client);
    }
    fh_add_client (fh, client);
    thread_mutex_unlock (&fh->lock);
    client->shared_data = fh;

    if (client->check_buffer == NULL)
        client->check_buffer = format_generic_write_to_client;

    client->ops = &buffer_content_ops;
    client->flags &= ~CLIENT_HAS_INTRO_CONTENT;
    client->flags |= CLIENT_IN_FSERVE;
    if (client->flags & CLIENT_ACTIVE)
    {
        client->schedule_ms = client->worker->time_ms;
        if (finfo && finfo->flags & FS_FALLBACK)
            return 0; // prevent a recursive loop 
        return client->ops->process (client);
    }
    else
    {
        worker_t *worker = client->worker;
        ret = (fh->finfo.limit) ? 0 : -1;
        client->flags |= CLIENT_ACTIVE;
        worker_wakeup (worker); /* worker may of already processed client but make sure */
    }
    return ret;
}
Beispiel #9
0
/** Initialize the firewall rules.
 */
int
iptables_fw_init(void)
{
	s_config *config;
	char * gw_interface = NULL;
	char * gw_address = NULL;
	char * gw_iprange = NULL;
	int gw_port = 0;
	int traffic_control;
	int set_mss, mss_value;
	t_MAC *pt;
	t_MAC *pb;
	t_MAC *pa;
	int rc = 0;
	int macmechanism;

	LOCK_CONFIG();
	config = config_get_config();
	gw_interface = safe_strdup(config->gw_interface); /* must free */
	gw_address = safe_strdup(config->gw_address);    /* must free */
	gw_iprange = safe_strdup(config->gw_iprange);    /* must free */
	gw_port = config->gw_port;
	pt = config->trustedmaclist;
	pb = config->blockedmaclist;
	pa = config->allowedmaclist;
	macmechanism = config->macmechanism;
	set_mss = config->set_mss;
	mss_value = config->mss_value;
	traffic_control = config->traffic_control;
	FW_MARK_BLOCKED = config->FW_MARK_BLOCKED;
	FW_MARK_TRUSTED = config->FW_MARK_TRUSTED;
	FW_MARK_AUTHENTICATED = config->FW_MARK_AUTHENTICATED;
	UNLOCK_CONFIG();


	/* Set up packet marking methods */
	rc |= _iptables_init_marks();
	rc |= _iptables_check_mark_masking();

	/*
	 *
	 **************************************
	 * Set up mangle table chains and rules
	 *
	 */

	/* Create new chains in the mangle table */
	rc |= iptables_do_command("-t mangle -N " CHAIN_TRUSTED); /* for marking trusted packets */
	rc |= iptables_do_command("-t mangle -N " CHAIN_BLOCKED); /* for marking blocked packets */
	rc |= iptables_do_command("-t mangle -N " CHAIN_INCOMING); /* for counting incoming packets */
	rc |= iptables_do_command("-t mangle -N " CHAIN_OUTGOING); /* for marking authenticated packets, and for counting outgoing packets */

	/* Assign jumps to these new chains */
	rc |= iptables_do_command("-t mangle -I PREROUTING 1 -i %s -s %s -j " CHAIN_OUTGOING, gw_interface, gw_iprange);
	rc |= iptables_do_command("-t mangle -I PREROUTING 2 -i %s -s %s -j " CHAIN_BLOCKED, gw_interface, gw_iprange);
	rc |= iptables_do_command("-t mangle -I PREROUTING 3 -i %s -s %s -j " CHAIN_TRUSTED, gw_interface, gw_iprange);
	rc |= iptables_do_command("-t mangle -I POSTROUTING 1 -o %s -d %s -j " CHAIN_INCOMING, gw_interface, gw_iprange);

	/* Rules to mark as trusted MAC address packets in mangle PREROUTING */
	for (; pt != NULL; pt = pt->next) {
		rc |= iptables_trust_mac(pt->mac);
	}

	/* Rules to mark as blocked MAC address packets in mangle PREROUTING */
	if (MAC_BLOCK == macmechanism) {
		/* with the MAC_BLOCK mechanism,
		 * MAC's on the block list are marked as blocked;
		 * everything else passes */
		for (; pb != NULL; pb = pb->next) {
			rc |= iptables_block_mac(pb->mac);
		}
	} else if (MAC_ALLOW == macmechanism) {
		/* with the MAC_ALLOW mechanism,
		 * MAC's on the allow list pass;
		 * everything else is to be marked as blocked */
		/* So, append at end of chain a rule to mark everything blocked */
		rc |= iptables_do_command("-t mangle -A " CHAIN_BLOCKED " -j MARK %s 0x%x", markop, FW_MARK_BLOCKED);
		/* But insert at beginning of chain rules to pass allowed MAC's */
		for (; pa != NULL; pa = pa->next) {
			rc |= iptables_allow_mac(pa->mac);
		}
	} else {
		debug(LOG_ERR, "Unknown MAC mechanism: %d", macmechanism);
		rc = -1;
	}

	/* Set up for traffic control */
	if (traffic_control) {
		rc |= tc_init_tc();
	}

	/*
	 * End of mangle table chains and rules
	 **************************************
	 */

	/*
	 *
	 **************************************
	 * Set up nat table chains and rules
	 *
	 */

	/* Create new chains in nat table */
	rc |= iptables_do_command("-t nat -N " CHAIN_OUTGOING);

	/*
	 * nat PREROUTING chain
	 */

	/* packets coming in on gw_interface jump to CHAIN_OUTGOING */
	rc |= iptables_do_command("-t nat -I PREROUTING -i %s -s %s -j " CHAIN_OUTGOING, gw_interface, gw_iprange);
	/* CHAIN_OUTGOING, packets marked TRUSTED  ACCEPT */
	rc |= iptables_do_command("-t nat -A " CHAIN_OUTGOING " -m mark --mark 0x%x%s -j ACCEPT", FW_MARK_TRUSTED, markmask);
	/* CHAIN_OUTGOING, packets marked AUTHENTICATED  ACCEPT */
	rc |= iptables_do_command("-t nat -A " CHAIN_OUTGOING " -m mark --mark 0x%x%s -j ACCEPT",FW_MARK_AUTHENTICATED, markmask);
	/* CHAIN_OUTGOING, append the "preauthenticated-users" ruleset */
	rc |= _iptables_append_ruleset("nat", "preauthenticated-users", CHAIN_OUTGOING);

	/* CHAIN_OUTGOING, packets for tcp port 80, redirect to gw_port on primary address for the iface */
	rc |= iptables_do_command("-t nat -A " CHAIN_OUTGOING " -p tcp --dport 80 -j DNAT --to-destination %s:%d", gw_address, gw_port);
	/* CHAIN_OUTGOING, other packets  ACCEPT */
	rc |= iptables_do_command("-t nat -A " CHAIN_OUTGOING " -j ACCEPT");

	/*
	 * End of nat table chains and rules
	 **************************************
	 */

	/*
	 *
	 **************************************
	 * Set up filter table chains and rules
	 *
	 */

	/* Create new chains in the filter table */
	rc |= iptables_do_command("-t filter -N " CHAIN_TO_INTERNET);
	rc |= iptables_do_command("-t filter -N " CHAIN_TO_ROUTER);
	rc |= iptables_do_command("-t filter -N " CHAIN_AUTHENTICATED);
	rc |= iptables_do_command("-t filter -N " CHAIN_TRUSTED);
	rc |= iptables_do_command("-t filter -N " CHAIN_TRUSTED_TO_ROUTER);

	/*
	 * filter INPUT chain
	 */

	/* packets coming in on gw_interface jump to CHAIN_TO_ROUTER */
	rc |= iptables_do_command("-t filter -I INPUT -i %s -s %s -j " CHAIN_TO_ROUTER, gw_interface, gw_iprange);
	/* CHAIN_TO_ROUTER packets marked BLOCKED  DROP */
	rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -m mark --mark 0x%x%s -j DROP", FW_MARK_BLOCKED, markmask);
	/* CHAIN_TO_ROUTER, invalid packets  DROP */
	rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -m conntrack --ctstate INVALID -j DROP");
	/* CHAIN_TO_ROUTER, related and established packets  ACCEPT */
	rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT");
	/* CHAIN_TO_ROUTER, bogus SYN packets  DROP */
	rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -p tcp --tcp-flags SYN SYN \\! --tcp-option 2 -j  DROP");

	/* CHAIN_TO_ROUTER, packets to HTTP listening on gw_port on router ACCEPT */
	rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -p tcp --dport %d -j ACCEPT", gw_port);

	/* CHAIN_TO_ROUTER, packets marked TRUSTED: */

	/* if trusted-users-to-router ruleset is empty:
	 *    use empty ruleset policy
	 * else:
	 *    jump to CHAIN_TRUSTED_TO_ROUTER, and load and use users-to-router ruleset
	 */
	if (is_empty_ruleset("trusted-users-to-router")) {
		rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -m mark --mark 0x%x%s -j %s", FW_MARK_TRUSTED, markmask, get_empty_ruleset_policy("trusted-users-to-router"));
	} else {
		rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -m mark --mark 0x%x%s -j " CHAIN_TRUSTED_TO_ROUTER, FW_MARK_TRUSTED, markmask);
		/* CHAIN_TRUSTED_TO_ROUTER, related and established packets  ACCEPT */
		rc |= iptables_do_command("-t filter -A " CHAIN_TRUSTED_TO_ROUTER " -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT");
		/* CHAIN_TRUSTED_TO_ROUTER, append the "trusted-users-to-router" ruleset */
		rc |= _iptables_append_ruleset("filter", "trusted-users-to-router", CHAIN_TRUSTED_TO_ROUTER);
		/* CHAIN_TRUSTED_TO_ROUTER, any packets not matching that ruleset  REJECT */
		rc |= iptables_do_command("-t filter -A " CHAIN_TRUSTED_TO_ROUTER " -j REJECT --reject-with icmp-port-unreachable");
	}

	/* CHAIN_TO_ROUTER, other packets: */

	/* if users-to-router ruleset is empty:
	 *    use empty ruleset policy
	 * else:
	 *    load and use users-to-router ruleset
	 */
	if (is_empty_ruleset("users-to-router")) {
		rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -j %s", get_empty_ruleset_policy("users-to-router"));
	} else {
		/* CHAIN_TO_ROUTER, append the "users-to-router" ruleset */
		rc |= _iptables_append_ruleset("filter", "users-to-router", CHAIN_TO_ROUTER);
		/* everything else, REJECT */
		rc |= iptables_do_command("-t filter -A " CHAIN_TO_ROUTER " -j REJECT --reject-with icmp-port-unreachable");

	}

	/*
	 * filter FORWARD chain
	 */

	/* packets coming in on gw_interface jump to CHAIN_TO_INTERNET */
	rc |= iptables_do_command("-t filter -I FORWARD -i %s -s %s -j " CHAIN_TO_INTERNET, gw_interface, gw_iprange);
	/* CHAIN_TO_INTERNET packets marked BLOCKED  DROP */
	rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m mark --mark 0x%x%s -j DROP", FW_MARK_BLOCKED, markmask);
	/* CHAIN_TO_INTERNET, invalid packets  DROP */
	rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m conntrack --ctstate INVALID -j DROP");
	/* CHAIN_TO_INTERNET, deal with MSS */
	if (set_mss) {
		/* XXX this mangles, so 'should' be done in the mangle POSTROUTING chain.
		 * However OpenWRT standard S35firewall does it in filter FORWARD,
		 * and since we are pre-empting that chain here, we put it in */
		if (mss_value > 0) { /* set specific MSS value */
			rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss %d", mss_value);
		} else { /* allow MSS as large as possible */
			rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu");
		}
	}

	/* CHAIN_TO_INTERNET, packets marked TRUSTED: */

	/* if trusted-users ruleset is empty:
	 *    use empty ruleset policy
	 * else:
	 *    jump to CHAIN_TRUSTED, and load and use trusted-users ruleset
	 */
	if (is_empty_ruleset("trusted-users")) {
		rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m mark --mark 0x%x%s -j %s", FW_MARK_TRUSTED, markmask, get_empty_ruleset_policy("trusted-users"));
	} else {
		rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m mark --mark 0x%x%s -j " CHAIN_TRUSTED, FW_MARK_TRUSTED, markmask);
		/* CHAIN_TRUSTED, related and established packets  ACCEPT */
		rc |= iptables_do_command("-t filter -A " CHAIN_TRUSTED " -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT");
		/* CHAIN_TRUSTED, append the "trusted-users" ruleset */
		rc |= _iptables_append_ruleset("filter", "trusted-users", CHAIN_TRUSTED);
		/* CHAIN_TRUSTED, any packets not matching that ruleset  REJECT */
		rc |= iptables_do_command("-t filter -A " CHAIN_TRUSTED " -j REJECT --reject-with icmp-port-unreachable");
	}


	/* CHAIN_TO_INTERNET, packets marked AUTHENTICATED: */

	/* if authenticated-users ruleset is empty:
	 *    use empty ruleset policy
	 * else:
	 *    jump to CHAIN_AUTHENTICATED, and load and use authenticated-users ruleset
	 */
	if (is_empty_ruleset("authenticated-users")) {
		rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m mark --mark 0x%x%s -j %s", FW_MARK_AUTHENTICATED, markmask, get_empty_ruleset_policy("authenticated-users"));
	} else {
		rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -m mark --mark 0x%x%s -j " CHAIN_AUTHENTICATED, FW_MARK_AUTHENTICATED, markmask);
		/* CHAIN_AUTHENTICATED, related and established packets  ACCEPT */
		rc |= iptables_do_command("-t filter -A " CHAIN_AUTHENTICATED " -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT");
		/* CHAIN_AUTHENTICATED, append the "authenticated-users" ruleset */
		rc |= _iptables_append_ruleset("filter", "authenticated-users", CHAIN_AUTHENTICATED);
		/* CHAIN_AUTHENTICATED, any packets not matching that ruleset  REJECT */
		rc |= iptables_do_command("-t filter -A " CHAIN_AUTHENTICATED " -j REJECT --reject-with icmp-port-unreachable");
	}

	/* CHAIN_TO_INTERNET, other packets: */

	/* if preauthenticated-users ruleset is empty:
	 *    use empty ruleset policy
	 * else:
	 *    load and use authenticated-users ruleset
	 */
	if (is_empty_ruleset("preauthenticated-users")) {
		rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -j %s ",  get_empty_ruleset_policy("preauthenticated-users"));
	} else {
		rc |= _iptables_append_ruleset("filter", "preauthenticated-users", CHAIN_TO_INTERNET);
	}
	/* CHAIN_TO_INTERNET, all other packets REJECT */
	rc |= iptables_do_command("-t filter -A " CHAIN_TO_INTERNET " -j REJECT --reject-with icmp-port-unreachable");

	/*
	 * End of filter table chains and rules
	 **************************************
	 */

	free(gw_interface);
	free(gw_iprange);
	free(gw_address);

	return rc;
}
Beispiel #10
0
/**@internal
 * Main execution loop
 */
static void
main_loop(void)
{
	int result = 0;
	pthread_t tid;
	s_config *config;

	config = config_get_config();

	/* Set the time when nodogsplash started */
	if (!started_time) {
		debug(LOG_INFO, "Setting started_time");
		started_time = time(NULL);
	} else if (started_time < MINIMUM_STARTED_TIME) {
		debug(LOG_WARNING, "Detected possible clock skew - re-setting started_time");
		started_time = time(NULL);
	}

	/* If we don't have the Gateway IP address, get it. Exit on failure. */
	if (!config->gw_address) {
		debug(LOG_DEBUG, "Finding IP address of %s", config->gw_interface);
		if ((config->gw_address = get_iface_ip(config->gw_interface)) == NULL) {
			debug(LOG_ERR, "Could not get IP address information of %s, exiting...", config->gw_interface);
			exit(1);
		}
	}
	if ((config->gw_mac = get_iface_mac(config->gw_interface)) == NULL) {
		debug(LOG_ERR, "Could not get MAC address information of %s, exiting...", config->gw_interface);
		exit(1);
	}
	debug(LOG_NOTICE, "Detected gateway %s at %s (%s)", config->gw_interface, config->gw_address, config->gw_mac);

	/* Initializes the web server */
	if ((webserver = MHD_start_daemon(
						MHD_USE_EPOLL_INTERNALLY,
						config->gw_port,
						NULL, NULL,
						libmicrohttpd_cb, NULL,
						MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120,
						MHD_OPTION_LISTENING_ADDRESS_REUSE, 1,
						MHD_OPTION_END)) == NULL) {
		debug(LOG_ERR, "Could not create web server: %s", strerror(errno));
		exit(1);
	}
	/* TODO: set listening socket */
	debug(LOG_NOTICE, "Created web server on %s:%d", config->gw_address, config->gw_port);
	/*
		httpdAddCContent(webserver, "/", "", 0, NULL, http_nodogsplash_callback_index);
		httpdAddCWildcardContent(webserver, config->authdir, NULL, http_nodogsplash_callback_auth);
		httpdAddCWildcardContent(webserver, config->denydir, NULL, http_nodogsplash_callback_deny);
		httpdAddC404Content(webserver, http_nodogsplash_callback_404);
	*/
	/* Reset the firewall (cleans it, in case we are restarting after nodogsplash crash) */

	fw_destroy();
	/* Then initialize it */
	debug(LOG_NOTICE, "Initializing firewall rules");
	if (fw_init() != 0) {
		debug(LOG_ERR, "Error initializing firewall rules! Cleaning up");
		fw_destroy();
		debug(LOG_ERR, "Exiting because of error initializing firewall rules");
		exit(1);
	}

	/* Start client statistics and timeout clean-up thread */
	result = pthread_create(&tid_client_check, NULL, thread_client_timeout_check, NULL);
	if (result != 0) {
		debug(LOG_ERR, "FATAL: Failed to create thread_client_timeout_check - exiting");
		termination_handler(0);
	}
	pthread_detach(tid_client_check);

	/* Start control thread */
	result = pthread_create(&tid, NULL, thread_ndsctl, (void *)(config->ndsctl_sock));
	if (result != 0) {
		debug(LOG_ERR, "FATAL: Failed to create thread_ndsctl - exiting");
		termination_handler(1);
	}

	result = pthread_join(tid, NULL);
	if (result) {
		debug(LOG_INFO, "Failed to wait for nodogsplash thread.");
	}
	MHD_stop_daemon(webserver);
	termination_handler(result);
}
Beispiel #11
0
/* client has requested a file, so check for it and send the file.  Do not
 * refer to the client_t afterwards.  return 0 for success, -1 on error.
 */
int fserve_client_create (client_t *httpclient, const char *path)
{
    struct stat file_buf;
    char *fullpath;
    int m3u_requested = 0, m3u_file_available = 1;
    int xspf_requested = 0, xspf_file_available = 1;
    int ret = -1;
    ice_config_t *config;
    fbinfo finfo;
    char fsize[20];

    fullpath = util_get_path_from_normalised_uri (path, 0);
    DEBUG2 ("checking for file %s (%s)", path, fullpath);

    if (strcmp (util_get_extension (fullpath), "m3u") == 0)
        m3u_requested = 1;

    if (strcmp (util_get_extension (fullpath), "xspf") == 0)
        xspf_requested = 1;

    /* check for the actual file */
    if (stat (fullpath, &file_buf) != 0)
    {
        /* the m3u can be generated, but send an m3u file if available */
        if (m3u_requested == 0 && xspf_requested == 0)
        {
            if (redirect_client (path, httpclient) == 0)
            {
                if ((httpclient->flags & CLIENT_SKIP_ACCESSLOG) == 0)
                    WARN2 ("req for file \"%s\" %s", fullpath, strerror (errno));
                ret = client_send_404 (httpclient, "The file you requested could not be found");
            }
            free (fullpath);
            return ret;
        }
        m3u_file_available = 0;
        xspf_file_available = 0;
    }

    client_set_queue (httpclient, NULL);
    httpclient->refbuf = refbuf_new (4096);

    if (m3u_requested && m3u_file_available == 0)
    {
        const char  *host = httpp_getvar (httpclient->parser, "host"),
                    *args = httpp_getvar (httpclient->parser, HTTPP_VAR_QUERYARGS),
                    *at = "", *user = "", *pass ="";
        char *sourceuri = strdup (path);
        char *dot = strrchr (sourceuri, '.');
        char *protocol = not_ssl_connection (&httpclient->connection) ? "http" : "https";
        const char *agent = httpp_getvar (httpclient->parser, "user-agent");
        int x;
        char scratch[1000];

        if (agent)
        {
            if (strstr (agent, "QTS") || strstr (agent, "QuickTime"))
                protocol = "icy";
        }
        /* at least a couple of players (fb2k/winamp) are reported to send a 
         * host header but without the port number. So if we are missing the
         * port then lets treat it as if no host line was sent */
        if (host && strchr (host, ':') == NULL)
            host = NULL;

        *dot = 0;
        if (httpclient->username && httpclient->password)
        {
            at = "@";
            user = httpclient->username;
            pass = httpclient->password;
        }
        httpclient->respcode = 200;
        if (host == NULL)
        {
            config = config_get_config();
            x = snprintf (scratch, sizeof scratch,
                    "%s://%s%s%s%s%s:%d%s%s\r\n",
                    protocol,
                    user, at[0]?":":"", pass, at,
                    config->hostname, config->port,
                    sourceuri,
                    args?args:"");
            config_release_config();
        }
        else
        {
            x = snprintf (scratch, sizeof scratch,
                    "%s://%s%s%s%s%s%s%s\r\n",
                    protocol,
                    user, at[0]?":":"", pass, at,
                    host,
                    sourceuri,
                    args?args:"");
        }
        snprintf (httpclient->refbuf->data, BUFSIZE,
                "HTTP/1.0 200 OK\r\n"
                "Content-Length: %d\r\n"
                "%s\r\n"
                "Content-Type: audio/x-mpegurl\r\n\r\n%s",
                x, client_keepalive_header (httpclient), scratch);
        httpclient->refbuf->len = strlen (httpclient->refbuf->data);
        free (sourceuri);
        free (fullpath);
        return fserve_setup_client_fb (httpclient, NULL);
    }
    if (xspf_requested && xspf_file_available == 0)
    {
        xmlDocPtr doc;
        char *reference = strdup (path);
        char *eol = strrchr (reference, '.');
        if (eol)
            *eol = '\0';
        doc = stats_get_xml (0, reference);
        free (reference);
        free (fullpath);
        return admin_send_response (doc, httpclient, XSLT, "xspf.xsl");
    }

    /* on demand file serving check */
    config = config_get_config();
    if (config->fileserve == 0)
    {
        config_release_config();
        DEBUG1 ("on demand file \"%s\" refused", fullpath);
        free (fullpath);
        return client_send_404 (httpclient, "The file you requested could not be found");
    }
    config_release_config();

    if (S_ISREG (file_buf.st_mode) == 0)
    {
        WARN1 ("found requested file but there is no handler for it: %s", fullpath);
        free (fullpath);
        return client_send_404 (httpclient, "The file you requested could not be found");
    }

    free (fullpath);
    finfo.flags = 0;
    finfo.mount = (char *)path;
    finfo.fallback = NULL;
    finfo.limit = 0;
    finfo.type = FORMAT_TYPE_UNDEFINED;
    snprintf (fsize, 20, "%" PRId64, (int64_t)file_buf.st_size);
    httpp_setvar (httpclient->parser, "__FILESIZE", fsize);
    stats_event_inc (NULL, "file_connections");

    return fserve_setup_client_fb (httpclient, &finfo);
}
Beispiel #12
0
int format_general_headers (format_plugin_t *plugin, client_t *client)
{
    unsigned remaining = 4096 - client->refbuf->len;
    char *ptr = client->refbuf->data + client->refbuf->len;
    int bytes;
    int bitrate_filtered = 0;
    avl_node *node;
    ice_config_t *config;

    if (client->respcode == 0)
    {
        const char *useragent = httpp_getvar (client->parser, "user-agent");
        const char *protocol = "HTTP/1.0";
        const char *contenttypehdr = "Content-Type";
        const char *contenttype = plugin->contenttype;

        if (useragent)
        {
            const char *resp = httpp_get_query_param (client->parser, "_hdr");
            int fmtcode = 0;
#define FMT_RETURN_ICY          1
#define FMT_LOWERCASE_TYPE      2
#define FMT_FORCE_AAC           4

            if (resp)
                fmtcode = atoi (resp);
            else
            {
                if (strstr (useragent, "shoutcastsource")) /* hack for mpc */
                    fmtcode = FMT_RETURN_ICY;
                if (strstr (useragent, "Windows-Media-Player")) /* hack for wmp*/
                    fmtcode = FMT_RETURN_ICY;
                if (strstr (useragent, "Shoutcast Server")) /* hack for sc_serv */
                    fmtcode = FMT_LOWERCASE_TYPE;
                // if (strstr (useragent, "Sonos"))
                //    contenttypehdr = "content-type";
                if (plugin->type == FORMAT_TYPE_AAC)
                {
                    if (strstr (useragent, "BlackBerry"))
                        fmtcode = FMT_FORCE_AAC;
                }
            }
            if (fmtcode & FMT_RETURN_ICY)
                protocol = "ICY";
            if (fmtcode & FMT_LOWERCASE_TYPE)
                contenttypehdr = "content-type";
            if (fmtcode & FMT_FORCE_AAC) // ie for avoiding audio/aacp
                contenttype = "audio/aac";
        }
        bytes = snprintf (ptr, remaining, "%s 200 OK\r\n"
                "%s: %s\r\n", protocol, contenttypehdr, contenttype);
        remaining -= bytes;
        ptr += bytes;
        client->respcode = 200;
    }

    if (plugin->parser)
    {
        /* iterate through source http headers and send to client */
        avl_tree_rlock (plugin->parser->vars);
        node = avl_get_first (plugin->parser->vars);
        while (node)
        {
            int next = 1;
            http_var_t *var = (http_var_t *)node->key;
            bytes = 0;
            if (!strcasecmp (var->name, "ice-audio-info"))
            {
                /* convert ice-audio-info to icy-br */
                char *brfield = NULL;
                unsigned int bitrate;

                if (bitrate_filtered == 0)
                    brfield = strstr (var->value, "bitrate=");
                if (brfield && sscanf (brfield, "bitrate=%u", &bitrate))
                {
                    bytes = snprintf (ptr, remaining, "icy-br:%u\r\n", bitrate);
                    next = 0;
                    bitrate_filtered = 1;
                }
                else
                    /* show ice-audio_info header as well because of relays */
                    bytes = snprintf (ptr, remaining, "%s: %s\r\n", var->name, var->value);
            }
            else
            {
                if (strcasecmp (var->name, "ice-password") &&
                        strcasecmp (var->name, "icy-metaint"))
                {
                    if (!strncasecmp ("ice-", var->name, 4))
                    {
                        if (!strcasecmp ("ice-public", var->name))
                            bytes = snprintf (ptr, remaining, "icy-pub:%s\r\n", var->value);
                        else
                            if (!strcasecmp ("ice-bitrate", var->name))
                                bytes = snprintf (ptr, remaining, "icy-br:%s\r\n", var->value);
                            else
                                bytes = snprintf (ptr, remaining, "icy%s:%s\r\n",
                                        var->name + 3, var->value);
                    }
                    else 
                        if (!strncasecmp ("icy-", var->name, 4))
                        {
                            bytes = snprintf (ptr, remaining, "icy%s:%s\r\n",
                                    var->name + 3, var->value);
                        }
                }
            }

            remaining -= bytes;
            ptr += bytes;
            if (next)
                node = avl_get_next (node);
        }
        avl_tree_unlock (plugin->parser->vars);
    }

    config = config_get_config();
    bytes = snprintf (ptr, remaining, "Server: %s\r\n", config->server_id);
    config_release_config();
    remaining -= bytes;
    ptr += bytes;

    /* prevent proxy servers from caching */
    bytes = snprintf (ptr, remaining, "Cache-Control: no-cache\r\n");
    remaining -= bytes;
    ptr += bytes;

    bytes = snprintf (ptr, remaining, "\r\n");
    remaining -= bytes;
    ptr += bytes;

    client->refbuf->len = 4096 - remaining;
    client->refbuf->flags |= WRITE_BLOCK_GENERIC;
    return 0;
}
Beispiel #13
0
static int command_manageauth (client_t *client, source_t *source, int response)
{
    xmlDocPtr doc;
    xmlNodePtr node, srcnode, msgnode;
    const char *action = NULL;
    const char *username = NULL;
    const char *message = NULL;
    int ret = AUTH_OK;
    ice_config_t *config = config_get_config ();
    mount_proxy *mountinfo = config_find_mount (config, source->mount);

    do
    { 
        if (mountinfo == NULL || mountinfo->auth == NULL)
        {
            WARN1 ("manage auth request for %s but no facility available", source->mount);
            break;
        }
        COMMAND_OPTIONAL (client, "action", action);
        COMMAND_OPTIONAL (client, "username", username);

        if (action == NULL)
            action = "list";

        if (!strcmp(action, "add"))
        {
            const char *password = NULL;
            COMMAND_OPTIONAL (client, "password", password);

            if (username == NULL || password == NULL)
            {
                WARN1 ("manage auth request add for %s but no user/pass", source->mount);
                break;
            }
            ret = mountinfo->auth->adduser(mountinfo->auth, username, password);
            if (ret == AUTH_FAILED) {
                message = "User add failed - check the icecast error log";
            }
            if (ret == AUTH_USERADDED) {
                message = "User added";
            }
            if (ret == AUTH_USEREXISTS) {
                message = "User already exists - not added";
            }
        }
        if (!strcmp(action, "delete"))
        {
            if (username == NULL)
            {
                WARN1 ("manage auth request delete for %s but no username", source->mount);
                break;
            }
            ret = mountinfo->auth->deleteuser(mountinfo->auth, username);
            if (ret == AUTH_FAILED) {
                message = "User delete failed - check the icecast error log";
            }
            if (ret == AUTH_USERDELETED) {
                message = "User deleted";
            }
        }

        doc = xmlNewDoc(XMLSTR "1.0");
        node = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL);
        srcnode = xmlNewChild(node, NULL, XMLSTR("source"), NULL);
        xmlSetProp(srcnode, XMLSTR "mount", XMLSTR(source->mount));
        thread_mutex_unlock (&source->lock);

        if (message) {
            msgnode = xmlNewChild(node, NULL, XMLSTR("iceresponse"), NULL);
            xmlNewChild(msgnode, NULL, XMLSTR "message", XMLSTR(message));
        }

        xmlDocSetRootElement(doc, node);

        if (mountinfo && mountinfo->auth && mountinfo->auth->listuser)
            mountinfo->auth->listuser (mountinfo->auth, srcnode);

        config_release_config ();

        return admin_send_response (doc, client, response, "manageauth.xsl");
    } while (0);

    thread_mutex_unlock (&source->lock);
    config_release_config ();
    return client_send_400 (client, "missing parameter");
}
Beispiel #14
0
/* build an XML doc containing information about currently running sources.
 * If a mountpoint is passed then that source will not be added to the XML
 * doc even if the source is running */
xmlDocPtr admin_build_sourcelist (const char *mount)
{
    avl_node *node;
    source_t *source;
    xmlNodePtr xmlnode, srcnode;
    xmlDocPtr doc;
    char buf[22];
    time_t now = time(NULL);

    doc = xmlNewDoc(XMLSTR("1.0"));
    xmlnode = xmlNewDocNode(doc, NULL, XMLSTR("icestats"), NULL);
    xmlDocSetRootElement(doc, xmlnode);

    if (mount) {
        xmlNewChild(xmlnode, NULL, XMLSTR("current_source"), XMLSTR(mount));
    }

    node = avl_get_first(global.source_tree);
    while(node) {
        source = (source_t *)node->key;
        if (mount && strcmp (mount, source->mount) == 0)
        {
            node = avl_get_next (node);
            continue;
        }

        thread_mutex_lock (&source->lock);
        if (source_available (source))
        {
            ice_config_t *config;
            mount_proxy *mountinfo;

            srcnode = xmlNewChild (xmlnode, NULL, XMLSTR("source"), NULL);
            xmlSetProp (srcnode, XMLSTR("mount"), XMLSTR(source->mount));

            snprintf (buf, sizeof(buf), "%lu", source->listeners);
            xmlNewChild (srcnode, NULL, XMLSTR("listeners"), XMLSTR(buf));

            config = config_get_config();
            mountinfo = config_find_mount (config, source->mount);
            if (mountinfo)
            {
                if (mountinfo->auth)
                {
                    xmlNewChild (srcnode, NULL, XMLSTR("authenticator"), 
                            XMLSTR(mountinfo->auth->type));
                }
                if (mountinfo->fallback_mount)
                    xmlNewChild (srcnode, NULL, XMLSTR("fallback"), 
                            XMLSTR(mountinfo->fallback_mount));
            }
            config_release_config();

            if (source_running (source))
            {
                if (source->client)
                {
                    snprintf (buf, sizeof(buf), "%lu",
                            (unsigned long)(now - source->client->connection.con_time));
                    xmlNewChild (srcnode, NULL, XMLSTR("Connected"), XMLSTR(buf));
                }
                xmlNewChild (srcnode, NULL, XMLSTR("content-type"), 
                        XMLSTR(source->format->contenttype));
            }
        }
        thread_mutex_unlock (&source->lock);
        node = avl_get_next(node);
    }
    return(doc);
}
Beispiel #15
0
int format_general_headers (format_plugin_t *plugin, client_t *client)
{
    unsigned remaining = 4096 - client->refbuf->len;
    char *ptr = client->refbuf->data + client->refbuf->len;
    int bytes = 0;
    int bitrate_filtered = 0;
    avl_node *node;
    ice_config_t *config;
    uint64_t length = 0; 

    /* hack for flash player, it wants a length. */
    if (httpp_getvar (client->parser, "x-flash-version"))
        length = 221183499;
    else
    {
        // flash may not send above header, so check for swf in referer
        const char *referer = httpp_getvar (client->parser, "referer");
        if (referer)
        {
            int len = strcspn (referer, "?");
            if (len >= 4 && strncmp (referer+len-4, ".swf", 4) == 0)
                length = 221183499;
        }
    }

    if (client->respcode == 0)
    {
        const char *useragent = httpp_getvar (client->parser, "user-agent");
        const char *protocol = "HTTP/1.0";
        const char *contenttypehdr = "Content-Type";
        const char *contenttype = plugin->contenttype;
        const char *range = httpp_getvar (client->parser, "range");
        const char *fs = httpp_getvar (client->parser, "__FILESIZE");

        if (useragent)
        {
            const char *resp = httpp_get_query_param (client->parser, "_hdr");
            int fmtcode = 0;
#define FMT_RETURN_ICY          1
#define FMT_LOWERCASE_TYPE      2
#define FMT_FORCE_AAC           4

            do
            {
                if (resp)
                {
                    fmtcode = atoi (resp);
                    break;
                }
                if (fs) break;  // ignore following settings for files.
                if (strstr (useragent, "shoutcastsource")) /* hack for mpc */
                    fmtcode = FMT_RETURN_ICY;
                if (strstr (useragent, "Windows-Media-Player")) /* hack for wmp*/
                    fmtcode = FMT_RETURN_ICY;
                if (strstr (useragent, "RealMedia")) /* hack for rp (mainly mobile) */
                    fmtcode = FMT_RETURN_ICY;
                if (strstr (useragent, "Shoutcast Server")) /* hack for sc_serv */
                    fmtcode = FMT_LOWERCASE_TYPE;
                // if (strstr (useragent, "Sonos"))
                //    contenttypehdr = "content-type";
                if (plugin->type == FORMAT_TYPE_AAC && strstr (useragent, "AppleWebKit"))
                    fmtcode |= FMT_FORCE_AAC;
                if (strstr (useragent, "BlackBerry"))
                {
                    fmtcode |= FMT_RETURN_ICY;
                    if (plugin->type == FORMAT_TYPE_AAC)
                        fmtcode |= FMT_FORCE_AAC;
                }
            } while (0);
            if (fmtcode & FMT_RETURN_ICY)
                protocol = "ICY";
            if (fmtcode & FMT_LOWERCASE_TYPE)
                contenttypehdr = "content-type";
            if (fmtcode & FMT_FORCE_AAC) // ie for avoiding audio/aacp
                contenttype = "audio/aac";
        }
        if (fs)
        {
            uint64_t pos1 = 0, pos2 = length ? length : 50000000, max = pos2;
            char buf[30];

            sscanf (fs, "%" SCNuMAX, &max);
            if (range)
            {
                if (strncmp (range, "bytes=-", 7) == 0)
                {
                    sscanf (range, "bytes=-%" SCNuMAX, &pos2);
                    pos1 = max-pos2;
                    pos2 = max-1;
                }
                else
                {
                    if (sscanf (range, "bytes=%" SCNuMAX "-%" SCNuMAX, &pos1, &pos2) < 2)
                        pos2 = max-1;
                }
                if (pos2 >= max || pos1 >= pos2)
                {
                    DEBUG2 ("client range invalid (%" PRIu64 ", %" PRIu64 ")", pos1, pos2);
                    return -1;
                }
                length = pos2 - pos1 + 1;
                snprintf (buf, 30, "%" PRIu64, length);
                httpp_setvar (client->parser, "__LENGTH", buf);
                client->respcode = 206;
                client->intro_offset = pos1;
                bytes = snprintf (ptr, remaining, "%s 206 Partial Content\r\n"
                        "%s: %s\r\n"
                        "Content-Length: %" PRIu64 "\r\n"
                        "Content-Range: bytes %" PRIu64 "-%" PRIu64 "/%" PRIu64 "\r\n",
                        protocol, contenttypehdr,
                        contenttype ? contenttype : "application/octet-stream",
                        length,
                        pos1, pos2, max);
            }
            else
            {
                client->respcode = 200;
                bytes = snprintf (ptr, remaining, "%s 200 OK\r\n"
                        "Content-Length: %" PRIu64 "\r\n"
                        "%s: %s\r\n", protocol, max, contenttypehdr, contenttype);
            }
        }
        else
        {
            client->respcode = 200;
            bytes = snprintf (ptr, remaining, "%s 200 OK\r\nAccept-Ranges: none\r\n"
                    "%s: %s\r\n", protocol, contenttypehdr, contenttype);
        }
        remaining -= bytes;
        ptr += bytes;
    }

    if (plugin && plugin->parser)
    {
        /* iterate through source http headers and send to client */
        avl_tree_rlock (plugin->parser->vars);
        node = avl_get_first (plugin->parser->vars);
        while (node)
        {
            int next = 1;
            http_var_t *var = (http_var_t *)node->key;
            bytes = 0;
            if (!strcasecmp (var->name, "ice-audio-info"))
            {
                /* convert ice-audio-info to icy-br */
                char *brfield = NULL;
                unsigned int bitrate;

                if (bitrate_filtered == 0)
                    brfield = strstr (var->value, "bitrate=");
                if (brfield && sscanf (brfield, "bitrate=%u", &bitrate))
                {
                    bytes = snprintf (ptr, remaining, "icy-br:%u\r\n", bitrate);
                    next = 0;
                    bitrate_filtered = 1;
                }
                else
                    /* show ice-audio_info header as well because of relays */
                    bytes = snprintf (ptr, remaining, "%s: %s\r\n", var->name, var->value);
            }
            else
            {
                if (strcasecmp (var->name, "ice-password") &&
                        strcasecmp (var->name, "icy-metaint"))
                {
                    if (!strncasecmp ("ice-", var->name, 4))
                    {
                        if (!strcasecmp ("ice-public", var->name))
                            bytes = snprintf (ptr, remaining, "icy-pub:%s\r\n", var->value);
                        else
                            if (!strcasecmp ("ice-bitrate", var->name))
                                bytes = snprintf (ptr, remaining, "icy-br:%s\r\n", var->value);
                            else
                                bytes = snprintf (ptr, remaining, "icy%s:%s\r\n",
                                        var->name + 3, var->value);
                    }
                    else 
                        if (!strncasecmp ("icy-", var->name, 4))
                        {
                            bytes = snprintf (ptr, remaining, "icy%s:%s\r\n",
                                    var->name + 3, var->value);
                        }
                }
            }

            remaining -= bytes;
            ptr += bytes;
            if (next)
                node = avl_get_next (node);
        }
        avl_tree_unlock (plugin->parser->vars);
    }

    config = config_get_config();
    bytes = snprintf (ptr, remaining, "Server: %s\r\n", config->server_id);
    config_release_config();
    remaining -= bytes;
    ptr += bytes;

    /* prevent proxy servers from caching */
    bytes = snprintf (ptr, remaining, "Cache-Control: no-cache, no-store\r\nPragma: no-cache\r\n"
            "Access-Control-Allow-Origin: *\r\n"
            "Access-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type\r\n"
            "Access-Control-Allow-Methods: GET, OPTIONS, HEAD\r\n"
            "Connection: close\r\n"
            "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n");
    remaining -= bytes;
    ptr += bytes;

    bytes = snprintf (ptr, remaining, "\r\n");
    remaining -= bytes;
    ptr += bytes;

    client->refbuf->len = 4096 - remaining;
    client->refbuf->flags |= WRITE_BLOCK_GENERIC;
    return 0;
}
Beispiel #16
0
/** Remove the firewall rules
 * This is used when we do a clean shutdown of nodogsplash,
 * and when it starts, to make sure there are no rules left over from a crash
 */
int
iptables_fw_destroy(void)
{
	fw_quiet = 1;
	s_config *config;
	int traffic_control;

	LOCK_CONFIG();
	config = config_get_config();
	traffic_control = config->traffic_control;
	UNLOCK_CONFIG();

	if (traffic_control) {
		debug(LOG_DEBUG, "Destroying our tc hooks");
		tc_destroy_tc();
	}

	debug(LOG_DEBUG, "Destroying our iptables entries");

	/*
	 *
	 * Everything in the mangle table
	 *
	 */
	debug(LOG_DEBUG, "Destroying chains in the MANGLE table");
	iptables_fw_destroy_mention("mangle", "PREROUTING", CHAIN_TRUSTED);
	iptables_fw_destroy_mention("mangle", "PREROUTING", CHAIN_BLOCKED);
	iptables_fw_destroy_mention("mangle", "PREROUTING", CHAIN_ALLOWED);
	iptables_fw_destroy_mention("mangle", "PREROUTING", CHAIN_OUTGOING);
	iptables_fw_destroy_mention("mangle", "POSTROUTING", CHAIN_INCOMING);
	iptables_do_command("-t mangle -F " CHAIN_TRUSTED);
	iptables_do_command("-t mangle -F " CHAIN_BLOCKED);
	iptables_do_command("-t mangle -F " CHAIN_ALLOWED);
	iptables_do_command("-t mangle -F " CHAIN_OUTGOING);
	iptables_do_command("-t mangle -F " CHAIN_INCOMING);
	iptables_do_command("-t mangle -X " CHAIN_TRUSTED);
	iptables_do_command("-t mangle -X " CHAIN_BLOCKED);
	iptables_do_command("-t mangle -X " CHAIN_ALLOWED);
	iptables_do_command("-t mangle -X " CHAIN_OUTGOING);
	iptables_do_command("-t mangle -X " CHAIN_INCOMING);

	/*
	 *
	 * Everything in the nat table
	 *
	 */

	debug(LOG_DEBUG, "Destroying chains in the NAT table");
	iptables_fw_destroy_mention("nat", "PREROUTING", CHAIN_OUTGOING);
	iptables_do_command("-t nat -F " CHAIN_OUTGOING);
	iptables_do_command("-t nat -X " CHAIN_OUTGOING);

	/*
	 *
	 * Everything in the filter table
	 *
	 */

	debug(LOG_DEBUG, "Destroying chains in the FILTER table");
	iptables_fw_destroy_mention("filter", "INPUT", CHAIN_TO_ROUTER);
	iptables_fw_destroy_mention("filter", "FORWARD", CHAIN_TO_INTERNET);
	iptables_do_command("-t filter -F " CHAIN_TO_ROUTER);
	iptables_do_command("-t filter -F " CHAIN_TO_INTERNET);
	iptables_do_command("-t filter -F " CHAIN_AUTHENTICATED);
	iptables_do_command("-t filter -F " CHAIN_TRUSTED);
	iptables_do_command("-t filter -F " CHAIN_TRUSTED_TO_ROUTER);
	iptables_do_command("-t filter -X " CHAIN_TO_ROUTER);
	iptables_do_command("-t filter -X " CHAIN_TO_INTERNET);
	iptables_do_command("-t filter -X " CHAIN_AUTHENTICATED);
	iptables_do_command("-t filter -X " CHAIN_TRUSTED);
	iptables_do_command("-t filter -X " CHAIN_TRUSTED_TO_ROUTER);

	return 0;
}
void connection_accept_loop(void)
{
    connection_t *con;

    if (!kitsune_is_updating()) /**DSU control */
        tid = thread_create("connection thread", _handle_connection, NULL, THREAD_ATTACHED);

    while (global.running == ICE_RUNNING)
    {
      kitsune_update("connection_accept"); /**DSU updatepoint */

        con = _accept_connection();

        if (con)
        {
            client_queue_t *node;
            ice_config_t *config;
            int i;
            client_t *client = NULL;

            global_lock();
            if (client_create (&client, con, NULL) < 0)
            {
                global_unlock();
                client_send_404 (client, "Icecast connection limit reached");
                continue;
            }
            global_unlock();

            /* setup client for reading incoming http */
            client->refbuf->data [PER_CLIENT_REFBUF_SIZE-1] = '\000';

            node = calloc (1, sizeof (client_queue_t));
            if (node == NULL)
            {
                client_destroy (client);
                continue;
            }
            node->client = client;

            /* Check for special shoutcast compatability processing */
            config = config_get_config();
            for (i = 0; i < global.server_sockets; i++)
            {
                if (global.serversock[i] == con->serversock)
                {
                    if (config->listeners[i].shoutcast_compat)
                        node->shoutcast = 1;
                }
            }
            config_release_config(); 

            sock_set_blocking (client->con->sock, SOCK_NONBLOCK);
            sock_set_nodelay (client->con->sock);

            _add_request_queue (node);
            stats_event_inc (NULL, "connections");
        }
        process_request_queue ();
    }

    /* Give all the other threads notification to shut down */
    thread_cond_broadcast(&global.shutdown_cond);

    if (tid)
        thread_join (tid);

    /* wait for all the sources to shutdown */
    thread_rwlock_wlock(&_source_shutdown_rwlock);
    thread_rwlock_unlock(&_source_shutdown_rwlock);
}
Beispiel #18
0
/** Update the counters of all the clients in the client list */
int
iptables_fw_counters_update(void)
{
	FILE *output;
	char *script,
		ip[INET6_ADDRSTRLEN],
		target[MAX_BUF];
	int rc;
	int af;
	s_config *config;
	unsigned long long int counter;
	t_client *p1;
	struct sockaddr_storage tempaddr;

	config = config_get_config();
	af = config->ip6 ? AF_INET6 : AF_INET;

	/* Look for outgoing traffic */
	safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " CHAIN_OUTGOING);
	output = popen(script, "r");
	free(script);
	if (!output) {
		debug(LOG_ERR, "popen(): %s", strerror(errno));
		return -1;
	}

	/* skip the first two lines */
	while (('\n' != fgetc(output)) && !feof(output)) {}
	while (('\n' != fgetc(output)) && !feof(output)) {}

	while ( !(feof(output) )) {
		rc = fscanf(output, "%*s %llu %s %*s %*s %*s %*s %15[0-9.]", &counter,target,ip);
		/* eat rest of line */
		while (('\n' != fgetc(output)) && !feof(output)) {}
		if (3 == rc && !strcmp(target,"MARK")) {
			/* Sanity*/
			if (!inet_pton(af, ip, &tempaddr)) {
				debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip);
				continue;
			}
			debug(LOG_DEBUG, "Read outgoing traffic for %s: Bytes=%llu", ip, counter);
			LOCK_CLIENT_LIST();
			if ((p1 = client_list_find_by_ip(ip))) {
				if ((p1->counters.outgoing - p1->counters.outgoing_history) < counter) {
					p1->counters.outgoing = p1->counters.outgoing_history + counter;
					p1->counters.last_updated = time(NULL);
					debug(LOG_DEBUG, "%s - Updated counter.outgoing to %llu bytes.  Updated last_updated to %d", ip, counter, p1->counters.last_updated);
				}
			} else {
				debug(LOG_WARNING, "Could not find %s in client list", ip);
			}
			UNLOCK_CLIENT_LIST();
		}
	}
	pclose(output);

	/* Look for incoming traffic */
	safe_asprintf(&script, "%s %s", "iptables", "-v -n -x -t mangle -L " CHAIN_INCOMING);
	output = popen(script, "r");
	free(script);
	if (!output) {
		debug(LOG_ERR, "popen(): %s", strerror(errno));
		return -1;
	}

	/* skip the first two lines */
	while (('\n' != fgetc(output)) && !feof(output)) {}
	while (('\n' != fgetc(output)) && !feof(output)) {}

	while ( !(feof(output) )) {
		rc = fscanf(output, "%*s %llu %s %*s %*s %*s %*s %*s %15[0-9.]", &counter,target,ip);
		/* eat rest of line */
		while (('\n' != fgetc(output)) && !feof(output)) {}
		if (3 == rc && !strcmp(target,"ACCEPT")) {
			/* Sanity*/
			if (!inet_pton(af, ip, &tempaddr)) {
				debug(LOG_WARNING, "I was supposed to read an IP address but instead got [%s] - ignoring it", ip);
				continue;
			}
			debug(LOG_DEBUG, "Read incoming traffic for %s: Bytes=%llu", ip, counter);
			LOCK_CLIENT_LIST();
			if ((p1 = client_list_find_by_ip(ip))) {
				if ((p1->counters.incoming - p1->counters.incoming_history) < counter) {
					p1->counters.incoming = p1->counters.incoming_history + counter;
					debug(LOG_DEBUG, "%s - Updated counter.incoming to %llu bytes", ip, counter);
				}
			} else {
				debug(LOG_WARNING, "Could not find %s in client list", ip);
			}
			UNLOCK_CLIENT_LIST();
		}
	}
	pclose(output);

	return 0;
}
static void _handle_get_request (client_t *client, char *passed_uri)
{
    int fileserve;
    int port;
    int i;
    char *serverhost = NULL;
    int serverport = 0;
    aliases *alias;
    ice_config_t *config;
    char *uri = passed_uri;

    config = config_get_config();
    fileserve = config->fileserve;
    port = config->port;
    for(i = 0; i < global.server_sockets; i++) {
        if(global.serversock[i] == client->con->serversock) {
            serverhost = config->listeners[i].bind_address;
            serverport = config->listeners[i].port;
            break;
        }
    }
    alias = config->aliases;

    /* there are several types of HTTP GET clients
    ** media clients, which are looking for a source (eg, URI = /stream.ogg)
    ** stats clients, which are looking for /admin/stats.xml
    ** and directory server authorizers, which are looking for /GUID-xxxxxxxx 
    ** (where xxxxxx is the GUID in question) - this isn't implemented yet.
    ** we need to handle the latter two before the former, as the latter two
    ** aren't subject to the limits.
    */
    /* TODO: add GUID-xxxxxx */

    /* Handle aliases */
    while(alias) {
        if(strcmp(uri, alias->source) == 0 && (alias->port == -1 || alias->port == serverport) && (alias->bind_address == NULL || (serverhost != NULL && strcmp(alias->bind_address, serverhost) == 0))) {
            uri = strdup (alias->destination);
            DEBUG2 ("alias has made %s into %s", passed_uri, uri);
            break;
        }
        alias = alias->next;
    }
    config_release_config();

    stats_event_inc(NULL, "client_connections");

    /* Dispatch all admin requests */
    if ((strcmp(uri, "/admin.cgi") == 0) ||
        (strncmp(uri, "/admin/", 7) == 0)) {
        admin_handle_request(client, uri);
        if (uri != passed_uri) free (uri);
        return;
    }

    /* Here we are parsing the URI request to see
    ** if the extension is .xsl, if so, then process
    ** this request as an XSLT request
    */
    if (util_check_valid_extension (uri) == XSLT_CONTENT)
    {
        /* If the file exists, then transform it, otherwise, write a 404 */
        DEBUG0("Stats request, sending XSL transformed stats");
        stats_transform_xslt (client, uri);
        if (uri != passed_uri) free (uri);
        return;
    }

    add_client (uri, client);
    if (uri != passed_uri) free (uri);
}
Beispiel #20
0
void config_shutdown(void) {
    config_get_config();
    config_clear(&_current_configuration);
    config_release_config();
    release_locks();
}
Beispiel #21
0
/* run along queue checking for any data that has come in or a timeout */
static void process_request_queue (void)
{
    client_queue_t **node_ref = (client_queue_t **)&_req_queue;
    ice_config_t *config = config_get_config ();
    int timeout = config->header_timeout;
    config_release_config();

    while (*node_ref)
    {
        client_queue_t *node = *node_ref;
        client_t *client = node->client;
        int len = PER_CLIENT_REFBUF_SIZE - 1 - node->offset;
        char *buf = client->refbuf->data + node->offset;

        if (len > 0)
        {
            if (client->con->con_time + timeout <= time(NULL))
                len = 0;
            else
                len = client_read_bytes (client, buf, len);
        }

        if (len > 0)
        {
            int pass_it = 1;
            char *ptr;

            /* handle \n, \r\n and nsvcap which for some strange reason has
             * EOL as \r\r\n */
            node->offset += len;
            client->refbuf->data [node->offset] = '\000';
            do
            {
                if (node->shoutcast == 1)
                {
                    /* password line */
                    if (strstr (client->refbuf->data, "\r\r\n") != NULL)
                        break;
                    if (strstr (client->refbuf->data, "\r\n") != NULL)
                        break;
                    if (strstr (client->refbuf->data, "\n") != NULL)
                        break;
                }
                /* stream_offset refers to the start of any data sent after the
                 * http style headers, we don't want to lose those */
                ptr = strstr (client->refbuf->data, "\r\r\n\r\r\n");
                if (ptr)
                {
                    node->stream_offset = (ptr+6) - client->refbuf->data;
                    break;
                }
                ptr = strstr (client->refbuf->data, "\r\n\r\n");
                if (ptr)
                {
                    node->stream_offset = (ptr+4) - client->refbuf->data;
                    break;
                }
                ptr = strstr (client->refbuf->data, "\n\n");
                if (ptr)
                {
                    node->stream_offset = (ptr+2) - client->refbuf->data;
                    break;
                }
                pass_it = 0;
            } while (0);

            if (pass_it)
            {
                if ((client_queue_t **)_req_queue_tail == &(node->next))
                    _req_queue_tail = (volatile client_queue_t **)node_ref;
                *node_ref = node->next;
                node->next = NULL;
                _add_connection (node);
                continue;
            }
        }
        else
        {
            if (len == 0 || client->con->error)
            {
                if ((client_queue_t **)_req_queue_tail == &node->next)
                    _req_queue_tail = (volatile client_queue_t **)node_ref;
                *node_ref = node->next;
                client_destroy (client);
                free (node);
                continue;
            }
        }
        node_ref = &node->next;
    }
    _handle_connection();
}
Beispiel #22
0
/**@internal
 * Main execution loop 
 */
static void
main_loop(void)
{
    int result;
    pthread_t tid;
    s_config *config = config_get_config();
    request *r;
    void **params;

    /* Set the time when wifidog started */
    if (!started_time) {
        debug(LOG_INFO, "Setting started_time");
        started_time = time(NULL);
    } else if (started_time < MINIMUM_STARTED_TIME) {
        debug(LOG_WARNING, "Detected possible clock skew - re-setting started_time");
        started_time = time(NULL);
    }

	/* save the pid file if needed */
    if ((!config) && (!config->pidfile))
        save_pid_file(config->pidfile);

    /* If we don't have the Gateway IP address, get it. Can't fail. */
    if (!config->gw_address) {
        debug(LOG_DEBUG, "Finding IP address of %s", config->gw_interface);
        if ((config->gw_address = get_iface_ip(config->gw_interface)) == NULL) {
            debug(LOG_ERR, "Could not get IP address information of %s, exiting...", config->gw_interface);
            exit(1);
        }
        debug(LOG_DEBUG, "%s = %s", config->gw_interface, config->gw_address);
    }

    /* If we don't have the Gateway ID, construct it from the internal MAC address.
     * "Can't fail" so exit() if the impossible happens. */
    if (!config->gw_id) {
        debug(LOG_DEBUG, "Finding MAC address of %s", config->external_interface);
        if ((config->gw_id = get_iface_mac(config->external_interface)) == NULL) {
            debug(LOG_ERR, "Could not get MAC address information of %s, exiting...", config->external_interface);
            exit(1);
        }
        debug(LOG_DEBUG, "%s = %s", config->gw_interface, config->gw_id);
    }

    /* Initializes the web server */
    debug(LOG_NOTICE, "Creating web server on %s:%d", config->gw_address, config->gw_port);
    if ((webserver = httpdCreate(config->gw_address, config->gw_port)) == NULL) {
        debug(LOG_ERR, "Could not create web server: %s", strerror(errno));
        exit(1);
    }
    register_fd_cleanup_on_fork(webserver->serverSock);

    debug(LOG_DEBUG, "Assigning callbacks to web server");

    httpdAddCContent(webserver, "/wifidog", "about", 0, NULL, http_callback_about);
    httpdAddCContent(webserver, "/wifidog", "status", 0, NULL, http_callback_status);
    httpdAddCContent(webserver, "/wifidog", "release", 0, NULL, http_callback_release);
    httpdAddCContent(webserver, "/wifidog", "allow", 0, NULL, http_callback_allow_redirect);

    httpdSetErrorFunction(webserver, 404, http_callback_404);

    /* Set the auth server ip address. */
    set_auth_svr_lastip(config);

    /* Reset the firewall (if WiFiDog crashed) */
    fw_destroy();
    /* Then initialize it */
    if (!fw_init()) {
        debug(LOG_ERR, "FATAL: Failed to initialize firewall");
        exit(1);
    }

    /* Start control thread */
    result = pthread_create(&tid, NULL, (void *)thread_wdctl, (void *)safe_strdup(config->wdctl_sock));
    if (result != 0) {
        debug(LOG_ERR, "FATAL: Failed to create a new thread (wdctl) - exiting");
        termination_handler(0);
    }
    pthread_detach(tid);


    debug(LOG_NOTICE, "Waiting for connections");
    while (1) {

        r = httpdGetConnection(webserver, NULL);

        /* We can't convert this to a switch because there might be
         * values that are not -1, 0 or 1. */
        if (webserver->lastError == -1) {
            /* Interrupted system call */
            if (NULL != r) {
                httpdEndRequest(r);
            }
        } else if (webserver->lastError < -1) {
            /*
             * FIXME
             * An error occurred - should we abort?
             * reboot the device ?
             */
            debug(LOG_ERR, "FATAL: httpdGetConnection returned unexpected value %d, exiting.", webserver->lastError);
            termination_handler(0);
        } else if (r != NULL) {
            /*
             * We got a connection
             *
             * We should create another thread
             */
            debug(LOG_INFO, "Received connection from %s, spawning worker thread", r->clientAddr);
            /* The void**'s are a simulation of the normal C
             * function calling sequence. */
            params = safe_malloc(2 * sizeof(void *));
            *params = webserver;
            *(params + 1) = r;


            result = pthread_create(&tid, NULL, (void *)thread_httpd, (void *)params);
            if (result != 0) {
                debug(LOG_ERR, "FATAL: Failed to create a new thread (httpd) - exiting");
                termination_handler(0);
            }
            pthread_detach(tid);
        } else {
            /* webserver->lastError should be 2 */
            /* XXX We failed an ACL.... No handling because
             * we don't set any... */
        }
        //update the auth server ip
        update_auth_svr_lastip(config);
    }

    /* never reached */
}
Beispiel #23
0
/* Called when activating a source. Verifies that the source count is not
 * exceeded and applies any initial parameters.
 */
int connection_complete_source (source_t *source, int response)
{
    ice_config_t *config;

    global_lock ();
    DEBUG1 ("sources count is %d", global.sources);

    config = config_get_config();
    if (global.sources < config->source_limit)
    {
        const char *contenttype;
        const char *expectcontinue;
        mount_proxy *mountinfo;
        format_type_t format_type;

        /* setup format handler */
        contenttype = httpp_getvar (source->parser, "content-type");
        if (contenttype != NULL)
        {
            format_type = format_get_type (contenttype);

            if (format_type == FORMAT_ERROR)
            {
                config_release_config();
                global_unlock();
                if (response)
                {
                    client_send_403 (source->client, "Content-type not supported");
                    source->client = NULL;
                }
                WARN1("Content-type \"%s\" not supported, dropping source", contenttype);
                return -1;
            }
        }
        else
        {
            WARN0("No content-type header, falling back to backwards compatibility mode "
                    "for icecast 1.x relays. Assuming content is mp3.");
            format_type = FORMAT_TYPE_GENERIC;
        }

        if (format_get_plugin (format_type, source) < 0)
        {
            global_unlock();
            config_release_config();
            if (response)
            {
                client_send_403 (source->client, "internal format allocation problem");
                source->client = NULL;
            }
            WARN1 ("plugin format failed for \"%s\"", source->mount);
            return -1;
        }

	/* For PUT support we check for 100-continue and send back a 100 to stay in spec */
	expectcontinue = httpp_getvar (source->parser, "expect");
	if (expectcontinue != NULL)
	{
#ifdef HAVE_STRCASESTR
	    if (strcasestr (expectcontinue, "100-continue") != NULL)
#else
	    WARN0("OS doesn't support case insenestive substring checks...");
	    if (strstr (expectcontinue, "100-continue") != NULL)
#endif
	    {
		client_send_100 (source->client);
	    }
	}

        global.sources++;
        stats_event_args (NULL, "sources", "%d", global.sources);
        global_unlock();

        source->running = 1;
        mountinfo = config_find_mount (config, source->mount, MOUNT_TYPE_NORMAL);
        source_update_settings (config, source, mountinfo);
        config_release_config();
        slave_rebuild_mounts();

        source->shutdown_rwlock = &_source_shutdown_rwlock;
        DEBUG0 ("source is ready to start");

        return 0;
    }
    WARN1("Request to add source when maximum source limit "
            "reached %d", global.sources);

    global_unlock();
    config_release_config();

    if (response)
    {
        client_send_403 (source->client, "too many sources connected");
        source->client = NULL;
    }

    return -1;
}
Beispiel #24
0
/* @internal
 * @brief During gateway restart, connects to the parent process via the internal socket
 * Downloads from it the active client list
 */
void
get_clients_from_parent(void)
{
    int sock;
    struct sockaddr_un sa_un;
    s_config *config = NULL;
    char linebuffer[MAX_BUF];
    int len = 0;
    char *running1 = NULL;
    char *running2 = NULL;
    char *token1 = NULL;
    char *token2 = NULL;
    char onechar;
    char *command = NULL;
    char *key = NULL;
    char *value = NULL;
    t_client *client = NULL;

    config = config_get_config();

    debug(LOG_INFO, "Connecting to parent to download clients");

    /* Connect to socket */
    sock = socket(AF_UNIX, SOCK_STREAM, 0);
    /* XXX An attempt to quieten coverity warning about the subsequent connect call:
     * Coverity says: "sock is apssed to parameter that cannot be negative"
     * Although connect expects a signed int, coverity probably tells us that it shouldn't
     * be negative */
    if (sock < 0) {
        debug(LOG_ERR, "Could not open socket (%s) - client list not downloaded", strerror(errno));
        return;
    }
    memset(&sa_un, 0, sizeof(sa_un));
    sa_un.sun_family = AF_UNIX;
    strncpy(sa_un.sun_path, config->internal_sock, (sizeof(sa_un.sun_path) - 1));

    if (connect(sock, (struct sockaddr *)&sa_un, strlen(sa_un.sun_path) + sizeof(sa_un.sun_family))) {
        debug(LOG_ERR, "Failed to connect to parent (%s) - client list not downloaded", strerror(errno));
        close(sock);
        return;
    }

    debug(LOG_INFO, "Connected to parent.  Downloading clients");

    LOCK_CLIENT_LIST();

    command = NULL;
    memset(linebuffer, 0, sizeof(linebuffer));
    len = 0;
    client = NULL;
    /* Get line by line */
    while (read(sock, &onechar, 1) == 1) {
        if (onechar == '\n') {
            /* End of line */
            onechar = '\0';
        }
        linebuffer[len++] = onechar;

        if (!onechar) {
            /* We have a complete entry in linebuffer - parse it */
            debug(LOG_DEBUG, "Received from parent: [%s]", linebuffer);
            running1 = linebuffer;
            while ((token1 = strsep(&running1, "|")) != NULL) {
                if (!command) {
                    /* The first token is the command */
                    command = token1;
                } else {
                    /* Token1 has something like "foo=bar" */
                    running2 = token1;
                    key = value = NULL;
                    while ((token2 = strsep(&running2, "=")) != NULL) {
                        if (!key) {
                            key = token2;
                        } else if (!value) {
                            value = token2;
                        }
                    }
                }

                if (strcmp(command, "CLIENT") == 0) {
                    /* This line has info about a client in the client list */
                    if (NULL == client) {
                        /* Create a new client struct */
                        client = client_get_new();
                    }
                }

                /* XXX client check to shut up clang... */
                if (key && value && client) {
                    if (strcmp(command, "CLIENT") == 0) {
                        /* Assign the key into the appropriate slot in the connection structure */
                        if (strcmp(key, "ip") == 0) {
                            client->ip = safe_strdup(value);
                        } else if (strcmp(key, "mac") == 0) {
                            client->mac = safe_strdup(value);
                        } else if (strcmp(key, "fw_connection_state") == 0) {
                            client->fw_connection_state = atoi(value);
                        } else if (strcmp(key, "fd") == 0) {
                            client->fd = atoi(value);
                        } else {
                            debug(LOG_NOTICE, "I don't know how to inherit key [%s] value [%s] from parent", key,
                                  value);
                        }
                    }
                }
            }

            /* End of parsing this command */
            if (client) {
                client_list_insert_client(client);
            }

            /* Clean up */
            command = NULL;
            memset(linebuffer, 0, sizeof(linebuffer));
            len = 0;
            client = NULL;
        }
    }

    UNLOCK_CLIENT_LIST();
    debug(LOG_INFO, "Client list downloaded successfully from parent");

    close(sock);
}
Beispiel #25
0
static auth_result url_add_listener (auth_client *auth_user)
{
    client_t *client = auth_user->client;
    auth_t *auth = client->auth;
    auth_url *url = auth->state;
    int res = 0, port;
    const char *agent;
    char *user_agent, *username, *password;
    const char *mountreq;
    char *mount, *ipaddr, *server;
    ice_config_t *config;
    char *userpwd = NULL, post [4096];
    ssize_t post_offset;
    char *pass_headers, *cur_header, *next_header;
    const char *header_val;
    char *header_valesc;

    if (url->addurl == NULL)
        return AUTH_OK;

    config = config_get_config ();
    server = util_url_escape (config->hostname);
    port = config->port;
    config_release_config ();

    agent = httpp_getvar (client->parser, "user-agent");
    if (agent)
        user_agent = util_url_escape (agent);
    else
        user_agent = strdup ("-");

    if (client->username)
        username = util_url_escape (client->username);
    else
        username = strdup ("");

    if (client->password)
        password = util_url_escape (client->password);
    else
        password = strdup ("");

    /* get the full uri (with query params if available) */
    mountreq = httpp_getvar (client->parser, HTTPP_VAR_RAWURI);
    if (mountreq == NULL)
        mountreq = httpp_getvar (client->parser, HTTPP_VAR_URI);
    mount = util_url_escape (mountreq);
    ipaddr = util_url_escape (client->con->ip);

    post_offset = snprintf (post, sizeof (post),
            "action=listener_add&server=%s&port=%d&client=%lu&mount=%s"
            "&user=%s&pass=%s&ip=%s&agent=%s",
            server, port, client->con->id, mount, username,
            password, ipaddr, user_agent);
    free (server);
    free (mount);
    free (user_agent);
    free (username);
    free (password);
    free (ipaddr);

    pass_headers = NULL;
    if (url->pass_headers)
        pass_headers = strdup (url->pass_headers);
    if (pass_headers)
    {
        cur_header = pass_headers;
        while (cur_header)
        {
	    next_header = strstr (cur_header, ",");
	    if (next_header)
	    {
		*next_header=0;
                next_header++;
	    }

            header_val = httpp_getvar (client->parser, cur_header);
            if (header_val)
            {
                header_valesc = util_url_escape (header_val);
                post_offset += snprintf (post+post_offset, sizeof (post)-post_offset, "&%s%s=%s",
                                         url->prefix_headers ? url->prefix_headers : "",
                                         cur_header, header_valesc);
                free (header_valesc);
            }

	    cur_header = next_header;
        }
    }

    if (strchr (url->addurl, '@') == NULL)
    {
        if (url->userpwd)
            curl_easy_setopt (url->handle, CURLOPT_USERPWD, url->userpwd);
        else
        {
            /* auth'd requests may not have a user/pass, but may use query args */
            if (client->username && client->password)
            {
                size_t len = strlen (client->username) + strlen (client->password) + 2;
                userpwd = malloc (len);
                snprintf (userpwd, len, "%s:%s", client->username, client->password);
                curl_easy_setopt (url->handle, CURLOPT_USERPWD, userpwd);
            }
            else
                curl_easy_setopt (url->handle, CURLOPT_USERPWD, "");
        }
    }
    else
    {
        /* url has user/pass but libcurl may need to clear any existing settings */
        curl_easy_setopt (url->handle, CURLOPT_USERPWD, "");
    }
    curl_easy_setopt (url->handle, CURLOPT_URL, url->addurl);
    curl_easy_setopt (url->handle, CURLOPT_POSTFIELDS, post);
    curl_easy_setopt (url->handle, CURLOPT_WRITEHEADER, auth_user);
    url->errormsg[0] = '\0';

    res = curl_easy_perform (url->handle);

    free (userpwd);

    if (res)
    {
        WARN2 ("auth to server %s failed with %s", url->addurl, url->errormsg);
        return AUTH_FAILED;
    }
    /* we received a response, lets see what it is */
    if (client->authenticated)
        return AUTH_OK;
    INFO2 ("client auth (%s) failed with \"%s\"", url->addurl, url->errormsg);
    return AUTH_FAILED;
}
Beispiel #26
0
/** Uses getopt() to parse the command line and set configuration values
 * also populates restartargv
 */
void
parse_commandline(int argc, char **argv)
{
    int c;
    int skiponrestart;
    int i;

    s_config *config = config_get_config();

    //MAGIC 3: Our own -x, the pid, and NULL :
    restartargv = safe_malloc((size_t) (argc + 3) * sizeof(char *));
    i = 0;
    restartargv[i++] = safe_strdup(argv[0]);

    while (-1 != (c = getopt(argc, argv, "c:hfd:sw:vx:i:a:"))) {

        skiponrestart = 0;

        switch (c) {

        case 'h':
            usage();
            exit(1);
            break;

        case 'c':
            if (optarg) {
                free(config->configfile);
                config->configfile = safe_strdup(optarg);
            }
            break;

        case 'w':
            if (optarg) {
                free(config->wdctl_sock);
                config->wdctl_sock = safe_strdup(optarg);
            }
            break;

        case 'f':
            skiponrestart = 1;
            config->daemon = 0;
            debugconf.log_stderr = 1;
            break;

        case 'd':
            if (optarg) {
                debugconf.debuglevel = atoi(optarg);
            }
            break;

        case 's':
            debugconf.log_syslog = 1;
            break;

        case 'v':
            fprintf(stdout, "This is WiFiDog-FFW version " VERSION "\n");
            exit(1);
            break;

        case 'x':
            skiponrestart = 1;
            if (optarg) {
                restart_orig_pid = atoi(optarg);
            } else {
                fprintf(stdout, "The expected PID to the -x switch was not supplied!");
                exit(1);
            }
            break;

        case 'i':
            if (optarg) {
                free(config->internal_sock);
                config->internal_sock = safe_strdup(optarg);
            }
            break;

        case 'a':
            if (optarg) {
                free(config->arp_table_path);
                config->arp_table_path = safe_strdup(optarg);
            } else {
                fprintf(stdout, "You must supply the path to the ARP table with -a!");
                exit(1);
            }
            break;
        default:
            usage();
            exit(1);
            break;

        }

        if (!skiponrestart) {
            /* Add it to restartargv */
            safe_asprintf(&(restartargv[i++]), "-%c", c);
            if (optarg) {
                restartargv[i++] = safe_strdup(optarg);
            }
        }

    }

    /* Finally, we should add  the -x, pid and NULL to restartargv
     * HOWEVER we cannot do it here, since this is called before we fork to background
     * so we'll leave this job to gateway.c after forking is completed
     * so that the correct PID is assigned
     *
     * We add 3 nulls, and the first 2 will be overridden later
     */
    restartargv[i++] = NULL;
    restartargv[i++] = NULL;
    restartargv[i++] = NULL;
}
Beispiel #27
0
/** Authenticates a single client against the central server and returns when done
 * Alters the firewall rules depending on what the auth server says
@param r httpd request struct
*/
void
authenticate_client(request *r)
{
	t_client	*client;
	t_authresponse	auth_response;
	char	*mac,
		*token;
	char *urlFragment = NULL;
	s_config	*config = NULL;
	t_auth_serv	*auth_server = NULL;
	httpVar *click_ad = httpdGetVariableByName(r, "click_ad");

	LOCK_CLIENT_LIST();

	client = client_list_find_by_ip(r->clientAddr);

	if (client == NULL) {
		debug(LOG_ERR, "authenticate_client(): Could not find client for %s", r->clientAddr);
		UNLOCK_CLIENT_LIST();
		return;
	}
	
	mac = safe_strdup(client->mac);
	token = safe_strdup(client->token);
	
	UNLOCK_CLIENT_LIST();
	
	/* 
	 * At this point we've released the lock while we do an HTTP request since it could
	 * take multiple seconds to do and the gateway would effectively be frozen if we
	 * kept the lock.
	 */
	auth_server_request(&auth_response, REQUEST_TYPE_LOGIN, r->clientAddr, mac, token, 0, 0);
	
	LOCK_CLIENT_LIST();
	
	/* can't trust the client to still exist after n seconds have passed */
	client = client_list_find(r->clientAddr, mac);
	
	if (client == NULL) {
		debug(LOG_ERR, "authenticate_client(): Could not find client node for %s (%s)", r->clientAddr, mac);
		UNLOCK_CLIENT_LIST();
		free(token);
		free(mac);
		return;
	}
	
	free(token);
	free(mac);

	/* Prepare some variables we'll need below */
	config = config_get_config();
	auth_server = get_auth_server();

	switch(auth_response.authcode) {

	case AUTH_ERROR:
		/* Error talking to central server */
		debug(LOG_ERR, "Got %d from central server authenticating token %s from %s at %s", auth_response, client->token, client->ip, client->mac);
		send_http_page(r, "Error!", "Error: We did not get a valid answer from the central server");
		break;

	case AUTH_DENIED:
		/* Central server said invalid token */
		debug(LOG_INFO, "Got DENIED from central server authenticating token %s from %s at %s - deleting from firewall and redirecting them to denied message", client->token, client->ip, client->mac);
		fw_deny(client->ip, client->mac, FW_MARK_KNOWN);
		safe_asprintf(&urlFragment, "%smessage=%s",
			auth_server->authserv_msg_script_path_fragment,
			GATEWAY_MESSAGE_DENIED
		);
		http_send_redirect_to_auth(r, urlFragment, "Redirect to denied message");
		free(urlFragment);
		break;

    case AUTH_VALIDATION:
		/* They just got validated for X minutes to check their email */
		debug(LOG_INFO, "Got VALIDATION from central server authenticating token %s from %s at %s"
				"- adding to firewall and redirecting them to activate message", client->token,
				client->ip, client->mac);
		client->fw_connection_state = FW_MARK_PROBATION;
		fw_allow(client->ip, client->mac, FW_MARK_PROBATION);
		safe_asprintf(&urlFragment, "%smessage=%s",
			auth_server->authserv_msg_script_path_fragment,
			GATEWAY_MESSAGE_ACTIVATE_ACCOUNT
		);
		http_send_redirect_to_auth(r, urlFragment, "Redirect to activate message");
		free(urlFragment);
	    break;

    case AUTH_ALLOWED:
		/* Logged in successfully as a regular account */
		debug(LOG_INFO, "Got ALLOWED from central server authenticating token %s from %s at %s - "
				"adding to firewall and redirecting them to portal", client->token, client->ip, client->mac);
		client->fw_connection_state = FW_MARK_KNOWN;
		fw_allow(client->ip, client->mac, FW_MARK_KNOWN);
        served_this_session++;
        if(click_ad != NULL)
        {
        	safe_asprintf(&urlFragment,"%sgw_id=%s&click_ad=%s",
        		auth_server->authserv_portal_script_path_fragment,
        		config->gw_id,
        		click_ad->value);
        }
        else 
        {
			safe_asprintf(&urlFragment, "%sgw_id=%s",
				auth_server->authserv_portal_script_path_fragment,
				config->gw_id
			);
		}
		http_send_redirect_to_auth(r, urlFragment, "Redirect to portal");
		free(urlFragment);
	    break;

    case AUTH_VALIDATION_FAILED:
		 /* Client had X minutes to validate account by email and didn't = too late */
		debug(LOG_INFO, "Got VALIDATION_FAILED from central server authenticating token %s from %s at %s "
				"- redirecting them to failed_validation message", client->token, client->ip, client->mac);
		safe_asprintf(&urlFragment, "%smessage=%s",
			auth_server->authserv_msg_script_path_fragment,
			GATEWAY_MESSAGE_ACCOUNT_VALIDATION_FAILED
		);
		http_send_redirect_to_auth(r, urlFragment, "Redirect to failed validation message");
		free(urlFragment);
	    break;

    default:
		debug(LOG_WARNING, "I don't know what the validation code %d means for token %s from %s at %s - sending error message", auth_response.authcode, client->token, client->ip, client->mac);
		send_http_page(r, "Internal Error", "We can not validate your request at this time");
	    break;

	}

	UNLOCK_CLIENT_LIST();
	return;
}
Beispiel #28
0
/** @internal
 * This function does the actual request.
 */
static void
ping(void)
{
    char request[MAX_BUF];
    FILE *fh;
    int sockfd;
    unsigned long int sys_uptime = 0;
    unsigned int sys_memfree = 0;
    float sys_load = 0;
    t_auth_serv *auth_server = NULL;
    auth_server = get_auth_server();
    static int authdown = 0;

    debug(LOG_DEBUG, "Entering ping()");
    memset(request, 0, sizeof(request));

    /*
     * The ping thread does not really try to see if the auth server is actually
     * working. Merely that there is a web server listening at the port. And that
     * is done by connect_auth_server() internally.
     */
    sockfd = connect_auth_server();
    if (sockfd == -1) {
        /*
         * No auth servers for me to talk to
         */
        if (!authdown) {
            fw_set_authdown();
            authdown = 1;
        }
        return;
    }

    /*
     * Populate uptime, memfree and load
     */
    if ((fh = fopen("/proc/uptime", "r"))) {
        if (fscanf(fh, "%lu", &sys_uptime) != 1)
            debug(LOG_CRIT, "Failed to read uptime");

        fclose(fh);
    }
    if ((fh = fopen("/proc/meminfo", "r"))) {
        while (!feof(fh)) {
            if (fscanf(fh, "MemFree: %u", &sys_memfree) == 0) {
                /* Not on this line */
                while (!feof(fh) && fgetc(fh) != '\n') ;
            } else {
                /* Found it */
                break;
            }
        }
        fclose(fh);
    }
    if ((fh = fopen("/proc/loadavg", "r"))) {
        if (fscanf(fh, "%f", &sys_load) != 1)
            debug(LOG_CRIT, "Failed to read loadavg");

        fclose(fh);
    }

    /*
     * Prep & send request
     */
    snprintf(request, sizeof(request) - 1,
             "GET %s%sgw_id=%s&sys_uptime=%lu&sys_memfree=%u&sys_load=%.2f&wifidog_uptime=%lu&prop=%s&network_id=%s&lat=%s&lon=%s&node_name=%s HTTP/1.0\r\n"
             "User-Agent: WiFiDog-ffw %s\r\n"
             "Host: %s\r\n"
             "\r\n",
             auth_server->authserv_path,
             auth_server->authserv_ping_script_path_fragment,
             config_get_config()->gw_id,
             sys_uptime,
             sys_memfree,
             sys_load,
             (long unsigned int)((long unsigned int)time(NULL) - (long unsigned int)started_time),
             config_get_config()->owner,
             config_get_config()->network,
             config_get_config()->lat,
             config_get_config()->lon,
             config_get_config()->node_name,
             VERSION, auth_server->authserv_hostname);

    char *res;
#ifdef USE_CYASSL
    if (auth_server->authserv_use_ssl) {
        res = https_get(sockfd, request, auth_server->authserv_hostname);
    } else {
        res = http_get(sockfd, request);
    }
#endif
#ifndef USE_CYASSL
    res = http_get(sockfd, request);
#endif
    if (NULL == res) {
        debug(LOG_ERR, "There was a problem pinging the auth server!");
        if (!authdown) {
            fw_set_authdown();
            authdown = 1;
        }
    } else if (strstr(res, "Pong") == 0) {
        debug(LOG_WARNING, "Auth server did NOT say Pong!");
        if (!authdown) {
            fw_set_authdown();
            authdown = 1;
        }
        free(res);
    } else {
        debug(LOG_DEBUG, "Auth Server Says: Pong");
        if (authdown) {
            fw_set_authup();
            authdown = 0;
        }
        free(res);
    }
    return;
}
Beispiel #29
0
void logging_access (client_t *client)
{
    ice_config_t *config = config_get_config();
    logging_access_id (&config->access_log, client);
    config_release_config ();
}
Beispiel #30
0
/* client has requested a file, so check for it and send the file.  Do not
 * refer to the client_t afterwards.  return 0 for success, -1 on error.
 */
int fserve_client_create (client_t *httpclient, const char *path)
{
    int bytes;
    struct stat file_buf;
    const char *range = NULL;
    off_t new_content_len = 0;
    off_t rangenumber = 0, content_length;
    int rangeproblem = 0;
    int ret = 0;
    char *fullpath;
    int m3u_requested = 0, m3u_file_available = 1;
    const char * xslt_playlist_requested = NULL;
    int xslt_playlist_file_available = 1;
    ice_config_t *config;
    FILE *file;

    fullpath = util_get_path_from_normalised_uri (path);
    INFO2 ("checking for file %H (%H)", path, fullpath);

    if (strcmp (util_get_extension (fullpath), "m3u") == 0)
        m3u_requested = 1;

    if (strcmp (util_get_extension (fullpath), "xspf") == 0)
        xslt_playlist_requested = "xspf.xsl";

    if (strcmp (util_get_extension (fullpath), "vclt") == 0)
        xslt_playlist_requested = "vclt.xsl";

    /* check for the actual file */
    if (stat (fullpath, &file_buf) != 0)
    {
        /* the m3u can be generated, but send an m3u file if available */
        if (m3u_requested == 0 && xslt_playlist_requested == NULL)
        {
            WARN2 ("req for file \"%H\" %s", fullpath, strerror (errno));
            client_send_404 (httpclient, "The file you requested could not be found");
            free (fullpath);
            return -1;
        }
        m3u_file_available = 0;
        xslt_playlist_file_available = 0;
    }

    httpclient->refbuf->len = PER_CLIENT_REFBUF_SIZE;

    if (m3u_requested && m3u_file_available == 0)
    {
        const char *host = httpp_getvar (httpclient->parser, "host");
        char *sourceuri = strdup (path);
        char *dot = strrchr(sourceuri, '.');

        /* at least a couple of players (fb2k/winamp) are reported to send a 
         * host header but without the port number. So if we are missing the
         * port then lets treat it as if no host line was sent */
        if (host && strchr (host, ':') == NULL)
            host = NULL;

        *dot = 0;
        httpclient->respcode = 200;
        if (host == NULL)
        {
            config = config_get_config();
            snprintf (httpclient->refbuf->data, BUFSIZE,
                    "HTTP/1.0 200 OK\r\n"
                    "Content-Type: audio/x-mpegurl\r\n\r\n"
                    "http://%s%s\r\n",
                    config->hostname,
                    sourceuri
                    );
            config_release_config();
        }
        else
        {
            snprintf (httpclient->refbuf->data, BUFSIZE,
                    "HTTP/1.0 200 OK\r\n"
                    "Content-Type: audio/x-mpegurl\r\n\r\n"
                    "http://%s%s\r\n", 
                    host, 
                    sourceuri
                    );
        }
        httpclient->refbuf->len = strlen (httpclient->refbuf->data);
        fserve_add_client (httpclient, NULL);
        free (sourceuri);
        free (fullpath);
        return 0;
    }
    if (xslt_playlist_requested && xslt_playlist_file_available == 0)
    {
        xmlDocPtr doc;
        char *reference = strdup (path);
        char *eol = strrchr (reference, '.');
        if (eol)
            *eol = '\0';
        doc = stats_get_xml (0, reference);
        free (reference);
        admin_send_response (doc, httpclient, TRANSFORMED, xslt_playlist_requested);
        xmlFreeDoc(doc);
        return 0;
    }

    /* on demand file serving check */
    config = config_get_config();
    if (config->fileserve == 0)
    {
        DEBUG1 ("on demand file \"%H\" refused", fullpath);
        client_send_404 (httpclient, "The file you requested could not be found");
        config_release_config();
        free (fullpath);
        return -1;
    }
    config_release_config();

    if (S_ISREG (file_buf.st_mode) == 0)
    {
        client_send_404 (httpclient, "The file you requested could not be found");
        WARN1 ("found requested file but there is no handler for it: %H", fullpath);
        free (fullpath);
        return -1;
    }

    file = fopen (fullpath, "rb");
    if (file == NULL)
    {
        WARN1 ("Problem accessing file \"%H\"", fullpath);
        client_send_404 (httpclient, "File not readable");
        free (fullpath);
        return -1;
    }
    free (fullpath);

    content_length = file_buf.st_size;
    range = httpp_getvar (httpclient->parser, "range");

    /* full http range handling is currently not done but we deal with the common case */
    if (range != NULL) {
        ret = 0;
        if (strncasecmp (range, "bytes=", 6) == 0)
            ret = sscanf (range+6, "%" SCN_OFF_T "-", &rangenumber);

        if (ret != 1) {
            /* format not correct, so lets just assume
               we start from the beginning */
            rangeproblem = 1;
        }
        if (rangenumber < 0) {
            rangeproblem = 1;
        }
        if (!rangeproblem) {
            ret = fseeko (file, rangenumber, SEEK_SET);
            if (ret != -1) {
                new_content_len = content_length - rangenumber;
                if (new_content_len < 0) {
                    rangeproblem = 1;
                }
            }
            else {
                rangeproblem = 1;
            }
            if (!rangeproblem) {
                /* Date: is required on all HTTP1.1 responses */
                char currenttime[50];
                time_t now;
                int strflen;
                struct tm result;
                off_t endpos = rangenumber+new_content_len-1;
                char *type;

                if (endpos < 0) {
                    endpos = 0;
                }
                time(&now);
                strflen = strftime(currenttime, 50, "%a, %d-%b-%Y %X GMT",
                                   gmtime_r(&now, &result));
                httpclient->respcode = 206;
                type = fserve_content_type (path);
                bytes = snprintf (httpclient->refbuf->data, BUFSIZE,
                    "HTTP/1.1 206 Partial Content\r\n"
                    "Date: %s\r\n"
                    "Accept-Ranges: bytes\r\n"
                    "Content-Length: %" PRI_OFF_T "\r\n"
                    "Content-Range: bytes %" PRI_OFF_T \
                    "-%" PRI_OFF_T "/%" PRI_OFF_T "\r\n"
                    "Content-Type: %s\r\n\r\n",
                    currenttime,
                    new_content_len,
                    rangenumber,
                    endpos,
                    content_length,
                    type);
                free (type);
            }
            else {
                goto fail;
            }
        }
        else {
            goto fail;
        }
    }
    else {
        char *type = fserve_content_type(path);
        httpclient->respcode = 200;
        bytes = snprintf (httpclient->refbuf->data, BUFSIZE,
            "HTTP/1.0 200 OK\r\n"
            "Accept-Ranges: bytes\r\n"
            "Content-Length: %" PRI_OFF_T "\r\n"
            "Content-Type: %s\r\n\r\n",
            content_length,
            type);
        free (type);
    }
    httpclient->refbuf->len = bytes;
    httpclient->pos = 0;

    stats_event_inc (NULL, "file_connections");
    fserve_add_client (httpclient, file);

    return 0;

fail:
    fclose (file);
    httpclient->respcode = 416;
    sock_write (httpclient->con->sock, 
            "HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n");
    client_destroy (httpclient);
    return -1;
}