*
* Purpose : Functions related to client-specific tags.
*
- * Copyright : Copyright (C) 2016 Fabian Keil <fk@fabiankeil.de>
+ * Copyright : Copyright (C) 2016-2017 Fabian Keil <fk@fabiankeil.de>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
#include "config.h"
+#ifdef FEATURE_CLIENT_TAGS
+
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include "jcc.h"
#include "miscutil.h"
#include "errlog.h"
+#include "parsers.h"
struct client_specific_tag
{
}
+/*********************************************************************
+ *
+ * Function : get_next_tag_timeout_for_client
+ *
+ * Description : Figures out when the next temporarily enabled tag
+ * for the client will have timed out.
+ *
+ * Parameters :
+ * 1 : client_address = Address of the client
+ *
+ * Returns : Lowest timeout in seconds
+ *
+ *********************************************************************/
+time_t get_next_tag_timeout_for_client(const char *client_address)
+{
+ struct client_specific_tag *enabled_tags;
+ time_t next_timeout = 0;
+ const time_t now = time(NULL);
+
+ privoxy_mutex_lock(&client_tags_mutex);
+
+ enabled_tags = get_tags_for_client(client_address);
+ while (enabled_tags != NULL)
+ {
+ log_error(LOG_LEVEL_CGI, "Evaluating tag '%s' for client %s. End of life %d",
+ enabled_tags->name, client_address, enabled_tags->end_of_life);
+ if (enabled_tags->end_of_life)
+ {
+ time_t time_left = enabled_tags->end_of_life - now;
+ /* Add a second to make sure the tag will have expired */
+ time_left++;
+ log_error(LOG_LEVEL_CGI, "%d > %d?", next_timeout, time_left);
+ if (next_timeout == 0 || next_timeout > time_left)
+ {
+ next_timeout = time_left;
+ }
+ }
+ enabled_tags = enabled_tags->next;
+ }
+
+ privoxy_mutex_unlock(&client_tags_mutex);
+
+ log_error(LOG_LEVEL_CGI, "Next timeout in %d seconds", next_timeout);
+
+ return next_timeout;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function : create_client_specific_tag
+ *
+ * Description : Allocates memory for a client specific tag
+ * and populates it.
+ *
+ * Parameters :
+ * 1 : name = The name of the tag to create.
+ * 2 : time_to_live = 0, or the number of seconds
+ * the tag remains activated.
+ *
+ * Returns : Pointer to populated tag
+ *
+ *********************************************************************/
+static struct client_specific_tag *create_client_specific_tag(const char *name,
+ const time_t time_to_live)
+{
+ struct client_specific_tag *tag;
+
+ tag = zalloc_or_die(sizeof(struct client_specific_tag));
+ tag->name = strdup_or_die(name);
+ tag->end_of_life = time_to_live ? (time(NULL) + time_to_live) : 0;
+
+ return tag;
+
+}
+
/*********************************************************************
*
* Function : add_tag_for_client
/* XXX: Code duplication. */
requested_tags = zalloc_or_die(sizeof(struct requested_tags));
requested_tags->client = strdup_or_die(client_address);
- requested_tags->tags = zalloc_or_die(sizeof(struct client_specific_tag));
- requested_tags->tags->name = strdup_or_die(tag);
- requested_tags->tags->end_of_life = time_to_live ?
- (time(NULL) + time_to_live) : 0;
+ requested_tags->tags = create_client_specific_tag(tag, time_to_live);
validate_requested_tags();
return;
clients_with_tags->next->prev = clients_with_tags;
clients_with_tags = clients_with_tags->next;
clients_with_tags->client = strdup_or_die(client_address);
- clients_with_tags->tags = zalloc_or_die(sizeof(struct client_specific_tag));
- clients_with_tags->tags->name = strdup_or_die(tag);
- clients_with_tags->tags->end_of_life = time_to_live ?
- (time(NULL) + time_to_live) : 0;
+ clients_with_tags->tags = create_client_specific_tag(tag, time_to_live);
validate_requested_tags();
{
if (enabled_tags->next == NULL)
{
- enabled_tags->next = zalloc_or_die(sizeof(struct client_specific_tag));
- enabled_tags->next->name = strdup_or_die(tag);
- clients_with_tags->tags->end_of_life = time_to_live ?
- (time(NULL) + time_to_live) : 0;
+ enabled_tags->next = create_client_specific_tag(tag, time_to_live);
enabled_tags->next->prev = enabled_tags;
break;
}
clients_with_tags = clients_with_tags->next;
}
+ assert(clients_with_tags != NULL);
+ if (clients_with_tags == NULL)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Tried to remove tag %s for tag-less client %s",
+ tag, client_address);
+ }
enabled_tags = clients_with_tags->tags;
while (enabled_tags != NULL)
{
/* Client has preceding client */
clients_with_tags->prev->next = clients_with_tags->next;
}
- freez(clients_with_tags->client);
if (clients_with_tags == requested_tags)
{
- /* Removing last tag */
- freez(requested_tags);
- clients_with_tags = requested_tags;
- }
- else
- {
- freez(clients_with_tags);
+ /*
+ * We're in the process of removing the last tag,
+ * mark the global list as empty.
+ */
+ requested_tags = NULL;
}
+ freez(clients_with_tags->client);
+ freez(clients_with_tags);
}
freez(enabled_tags->name);
freez(enabled_tags);
return JB_ERR_PARSE;
}
- if (client_has_requested_tag(csp->ip_addr_str, tag_name))
+ if (client_has_requested_tag(csp->client_address, tag_name))
{
log_error(LOG_LEVEL_ERROR,
- "Tag '%s' already enabled for client '%s'", tag->name, csp->ip_addr_str);
+ "Tag '%s' already enabled for client '%s'", tag->name, csp->client_address);
}
else
{
- add_tag_for_client(csp->ip_addr_str, tag_name, time_to_live);
+ add_tag_for_client(csp->client_address, tag_name, time_to_live);
log_error(LOG_LEVEL_INFO,
- "Tag '%s' enabled for client '%s'", tag->name, csp->ip_addr_str);
+ "Tag '%s' enabled for client '%s'. TTL: %d.",
+ tag->name, csp->client_address, time_to_live);
}
privoxy_mutex_unlock(&client_tags_mutex);
return JB_ERR_PARSE;
}
- if (client_has_requested_tag(csp->ip_addr_str, tag_name))
+ if (client_has_requested_tag(csp->client_address, tag_name))
{
- remove_tag_for_client(csp->ip_addr_str, tag_name);
+ remove_tag_for_client(csp->client_address, tag_name);
log_error(LOG_LEVEL_INFO,
- "Tag '%s' disabled for client '%s'", tag->name, csp->ip_addr_str);
+ "Tag '%s' disabled for client '%s'", tag->name, csp->client_address);
}
else
{
log_error(LOG_LEVEL_ERROR,
"Tag '%s' currently not set for client '%s'",
- tag->name, csp->ip_addr_str);
+ tag->name, csp->client_address);
}
privoxy_mutex_unlock(&client_tags_mutex);
return 0;
}
+
+
+/*********************************************************************
+ *
+ * Function : set_client_address
+ *
+ * Description : Sets the client address that will be used to enable,
+ * disable, or apply client tags.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : headers = Client headers
+ *
+ * Returns : void.
+ *
+ *********************************************************************/
+void set_client_address(struct client_state *csp, const struct list *headers)
+{
+ if (csp->config->trust_x_forwarded_for)
+ {
+ const char *client_address;
+
+ client_address = get_header_value(headers, "X-Forwarded-For:");
+ if (client_address != NULL)
+ {
+ csp->client_address = strdup_or_die(client_address);
+ log_error(LOG_LEVEL_HEADER,
+ "Got client address %s from X-Forwarded-For header",
+ csp->client_address);
+ }
+ }
+
+ if (csp->client_address == NULL)
+ {
+ csp->client_address = strdup_or_die(csp->ip_addr_str);
+ }
+}
+
+#else
+#error Compiling client-tags.c without FEATURE_CLIENT_TAGS
+#endif /* def FEATURE_CLIENT_TAGS */