/* This file is part of varnish-mib -*- c -*-
Copyright (C) 2014-2015 Sergey Poznyakoff
Varnish-mib is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
Varnish-mib is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with varnish-mib. If not, see .
*/
#include "varnish_mib.h"
#include
static int
send_ban_cmd(vcli_conn_t *conn, const char *expr)
{
if (vcli_asprintf(conn, "ban %s\n", expr) || vcli_write(conn))
return 1;
if (vcli_read_response(conn))
return 1;
if (conn->resp != CLIS_OK) {
snmp_log(LOG_ERR, "command rejected: %u %s\n",
conn->resp, conn->base);
return 1;
}
return 0;
}
int
varnish_ban(netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests,
struct vsm *vsm)
{
int rc;
struct vcli_conn conn;
size_t len = requests->requestvb->val_len;
char *expr = malloc(len + 1);
if (!expr) {
snmp_log(LOG_ERR, "out of memory\n");
return SNMP_ERR_GENERR;
}
memcpy(expr, requests->requestvb->val.string, len);
expr[len] = 0;
DEBUGMSGTL(("varnish_ban", "setting ban %s\n", expr));
rc = vcli_connect(vsm, &conn);
if (rc == SNMP_ERR_NOERROR) {
rc = send_ban_cmd(&conn, expr);
vcli_disconnect(&conn);
}
free(expr);
return rc ? SNMP_ERR_GENERR : SNMP_ERR_NOERROR;
}
unsigned banTable_timeout = 60;
int
varnish_mib_timeout_parser(const char *token, char *line, unsigned *retval)
{
char *p;
unsigned long n = strtoul(line, &p, 10);
if (*p) {
if (isspace(*p)) {
while (*p && isspace(*p))
++p;
if (*p) {
config_perror("too many arguments");
return 1;
}
} else {
config_perror("invalid timeout value");
return 1;
}
}
if (n > UINT_MAX) {
config_perror("timeout value out of allowed range");
return 1;
}
*retval = n;
return 0;
}
void
varnish_ban_table_timeout_parser(const char *token, char *line)
{
varnish_mib_timeout_parser(token, line, &banTable_timeout);
}
/*
* create a new row in the table
*/
static struct banTable_entry *
create_entry(netsnmp_tdata *table_data, long idx, struct banTable_entry *ent)
{
struct banTable_entry *entry;
netsnmp_tdata_row *row;
entry = SNMP_MALLOC_TYPEDEF(struct banTable_entry);
if (!entry)
return NULL;
row = netsnmp_tdata_create_row();
if (!row) {
SNMP_FREE(entry);
return NULL;
}
row->data = entry;
*entry = *ent;
entry->banIndex = idx;
netsnmp_tdata_row_add_index(row, ASN_INTEGER,
&entry->banIndex,
sizeof(entry->banIndex));
if (table_data)
netsnmp_tdata_add_row(table_data, row);
return entry;
}
#define TMSEC(t) (((t)->tm_hour * 60 + (t)->tm_min) * 60 + (t)->tm_sec)
static int
utc_offset (void)
{
time_t t = time (NULL);
struct tm ltm = *localtime (&t);
struct tm gtm = *gmtime (&t);
int d = TMSEC (<m) - TMSEC (>m);
if (!(ltm.tm_year = gtm.tm_year && ltm.tm_mon == gtm.tm_mon))
d += 86400;
return d / 60;
}
/* Refill the ban table */
int
banTable_load(netsnmp_cache *cache, void *vmagic)
{
netsnmp_tdata *table = (netsnmp_tdata *) vmagic;
long idx = 0;
int rc;
struct vcli_conn conn;
char *p;
struct vsm *vsm = varnish_get_vsm_data();
if (!vsm)
return SNMP_ERR_GENERR;
DEBUGMSGTL(("varnish_ban", "reloading ban table\n"));
rc = vcli_connect(vsm, &conn);
if (rc != SNMP_ERR_NOERROR)
return rc;
if (vcli_asprintf(&conn, "ban.list\n") || vcli_write(&conn))
return SNMP_ERR_GENERR;
if (vcli_read_response(&conn))
return SNMP_ERR_GENERR;
if (conn.resp != CLIS_OK) {
snmp_log(LOG_ERR, "ban.list command rejected: %u %s\n",
conn.resp, conn.base);
return SNMP_ERR_GENERR;
}
p = conn.base;
while (p < conn.base + conn.bufsize) {
char *q;
struct banTable_entry e;
struct tm *tm;
time_t t;
int n;
if (*p == '\n') {
++p;
continue;
}
e.banIndex = idx;
t = strtoul(p, &q, 10);
if (*q != '.') {
p = strchr(p, '\n');
if (!p)
break;
continue;
}
++q;
e.banTime_len = 11;
e.banTime = malloc(e.banTime_len + 1);
if (!e.banTime) {
vcli_disconnect(&conn);
snmp_log(LOG_ERR, "out of memory\n");
return SNMP_ERR_GENERR;
}
tm = localtime(&t);
/* A date-time specification.
field octets contents range
----- ------ -------- -----
1 1-2 year* 0..65536
2 3 month 1..12
3 4 day 1..31
4 5 hour 0..23
5 6 minutes 0..59
6 7 seconds 0..60
(use 60 for leap-second)
7 8 deci-seconds 0..9
8 9 direction from UTC '+' / '-'
9 10 hours from UTC* 0..13
10 11 minutes from UTC 0..59
* Notes:
- the value of year is in network-byte order
*/
n = tm->tm_year % 100;
e.banTime[0] = n >> 8;
e.banTime[1] = n & 0xff;
e.banTime[2] = tm->tm_mon + 1;
e.banTime[3] = tm->tm_mday;
e.banTime[4] = tm->tm_hour;
e.banTime[5] = tm->tm_min;
e.banTime[6] = tm->tm_sec;
e.banTime[7] = *q - '0';
n = utc_offset();
if (n < 0) {
e.banTime[8] = '-';
n = - n;
} else
e.banTime[8] = '+';
e.banTime[9] = n / 60;
e.banTime[10] = n % 60;
while (*q && isdigit(*q))
++q;
while (*q && isspace(*q))
++q;
e.banRefCount = strtoul(q, &q, 10);
while (*q && isspace(*q))
++q;
e.banExpression_len = strcspn(q, "\n");
e.banExpression = malloc(e.banExpression_len);
if (!e.banExpression) {
vcli_disconnect(&conn);
free(e.banTime);
snmp_log(LOG_ERR, "out of memory\n");
return SNMP_ERR_GENERR;
}
memcpy(e.banExpression, q, e.banExpression_len);
create_entry(table, idx, &e);
++idx;
q += e.banExpression_len;
p = q;
}
vcli_disconnect(&conn);
DEBUGMSGTL(("varnish_ban", "loaded %ld ban entries\n", idx));
return 0;
}
void
banTable_free(netsnmp_cache *cache, void *vmagic)
{
netsnmp_tdata *table = (netsnmp_tdata *) vmagic;
netsnmp_tdata_row *row;
DEBUGMSGTL(("varnish_ban", "freeing ban table\n"));
while ((row = netsnmp_tdata_row_first(table))) {
struct banTable_entry *entry = row->data;
free(entry->banExpression);
free(entry->banTime);
SNMP_FREE(entry);
netsnmp_tdata_remove_and_delete_row(table, row);
}
}