summaryrefslogtreecommitdiffabout
path: root/src
authorSergey Poznyakoff <gray@gnu.org.ua>2014-11-18 23:49:13 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2014-11-19 00:03:58 (GMT)
commit57a7d63793de517493499e748ce5d5d82def8a57 (patch) (unidiff)
tree35dbead6db811eecc03c0578e8aa3e2ed777b824 /src
parentf0671d1bc19592e5b659959920b51e3da05de79f (diff)
downloadvarnish-mib-57a7d63793de517493499e748ce5d5d82def8a57.tar.gz
varnish-mib-57a7d63793de517493499e748ce5d5d82def8a57.tar.bz2
New rw snmp variable clientBan allows to set bans via snmp
* src/varnish_mib.mib2c: Add support for rw variables. * src/Makefile.am (varnish_mib_la_SOURCES): Add new files. * src/VARNISH-MIB.txt (clientBan): New OID. * src/auth.c: New file. * src/ban.c: New file. * src/sha256.c: New file. * src/sha256.h: New file. * src/varnish_mib.h: New file. * src/vcli.c: New file.
Diffstat (limited to 'src') (more/less context) (ignore whitespace changes)
-rw-r--r--src/Makefile.am8
-rw-r--r--src/VARNISH-MIB.txt9
-rw-r--r--src/auth.c63
-rw-r--r--src/ban.c62
-rw-r--r--src/sha256.c570
-rw-r--r--src/sha256.h91
-rw-r--r--src/varnish_mib.h52
-rw-r--r--src/varnish_mib.mib2c173
-rw-r--r--src/vcli.c499
9 files changed, 1481 insertions, 46 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 4efd22c..439cdb3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,7 +18,13 @@ dlmoddir=@DLMODDIR@
18dlmod_LTLIBRARIES = varnish-mib.la 18dlmod_LTLIBRARIES = varnish-mib.la
19 19
20varnish_mib_la_SOURCES = \ 20varnish_mib_la_SOURCES = \
21 varnish_mib.c 21 auth.c\
22 ban.c\
23 sha256.c\
24 sha256.h\
25 varnish_mib.c\
26 varnish_mib.h\
27 vcli.c
22 28
23BUILT_SOURCES = \ 29BUILT_SOURCES = \
24 varnish_mib.c 30 varnish_mib.c
diff --git a/src/VARNISH-MIB.txt b/src/VARNISH-MIB.txt
index 0ec5dac..01def5c 100644
--- a/src/VARNISH-MIB.txt
+++ b/src/VARNISH-MIB.txt
@@ -70,6 +70,14 @@ clientCacheMisses OBJECT-TYPE
70 "Cache misses" 70 "Cache misses"
71 ::= { client 5 } 71 ::= { client 5 }
72 72
73clientBan OBJECT-TYPE
74 SYNTAXOCTET STRING (SIZE(0..1024))
75 MAX-ACCESS read-write
76 STATUS current
77 DESCRIPTION
78 "FIXME"
79 ::= { client 6 }
80
73connections OBJECT IDENTIFIER ::= { backend 1 } 81connections OBJECT IDENTIFIER ::= { backend 1 }
74 82
75backendConnSuccess OBJECT-TYPE 83backendConnSuccess OBJECT-TYPE
@@ -201,6 +209,7 @@ varnishGroup OBJECT-GROUP
201 clientCacheHits, 209 clientCacheHits,
202 clientCacheHitsPass, 210 clientCacheHitsPass,
203 clientCacheMisses, 211 clientCacheMisses,
212 clientBan,
204 backendConnSuccess, 213 backendConnSuccess,
205 backendConnNotAttempted, 214 backendConnNotAttempted,
206 backendConnToMany, 215 backendConnToMany,
diff --git a/src/auth.c b/src/auth.c
new file mode 100644
index 0000000..9ef90ac
--- a/dev/null
+++ b/src/auth.c
@@ -0,0 +1,63 @@
1/* This file is part of varnish-mib -*- c -*-
2 Copyright (C) 2014 Sergey Poznyakoff
3
4 Varnish-mib is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 Varnish-mib is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with varnish-mib. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "varnish_mib.h"
19#include "sha256.h"
20#include <unistd.h>
21#include <fcntl.h>
22#include <assert.h>
23#include <errno.h>
24
25void
26varnish_auth_response_fd(int fd, const char *challenge,
27 char response[CLI_AUTH_RESPONSE_LEN + 1])
28{
29 struct sha256_ctx ctx;
30 uint8_t buf[BUFSIZ];
31 int i;
32
33 assert(CLI_AUTH_RESPONSE_LEN == (SHA256_DIGEST_SIZE * 2));
34
35 sha256_init_ctx(&ctx);
36 sha256_process_bytes(challenge, 32, &ctx);
37 sha256_process_bytes("\n", 1, &ctx);
38 do {
39 i = read(fd, buf, sizeof buf);
40 if (i > 0)
41 sha256_process_bytes(buf, i, &ctx);
42 } while (i > 0);
43 sha256_process_bytes(challenge, 32, &ctx);
44 sha256_process_bytes("\n", 1, &ctx);
45 sha256_finish_ctx(&ctx, buf);
46 for (i = 0; i < SHA256_DIGEST_SIZE; i++)
47 sprintf(response + 2 * i, "%02x", buf[i]);
48}
49
50int
51varnish_auth_response(const char *file, const char *challenge,
52 char response[CLI_AUTH_RESPONSE_LEN + 1])
53{
54 int fd = open(file, O_RDONLY);
55 if (fd == -1) {
56 snmp_log(LOG_ERR, "can't open secret file %s: %s\n",
57 file, strerror(errno));
58 return -1;
59 }
60 varnish_auth_response_fd(fd, challenge, response);
61 close(fd);
62 return 0;
63}
diff --git a/src/ban.c b/src/ban.c
new file mode 100644
index 0000000..a091e37
--- a/dev/null
+++ b/src/ban.c
@@ -0,0 +1,62 @@
1/* This file is part of varnish-mib -*- c -*-
2 Copyright (C) 2014 Sergey Poznyakoff
3
4 Varnish-mib is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 Varnish-mib is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with varnish-mib. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "varnish_mib.h"
19
20static int
21send_ban_cmd(vcli_conn_t *conn, const char *expr)
22{
23 if (vcli_asprintf(conn, "ban %s\n", expr) || vcli_write(conn))
24 return 1;
25
26 if (vcli_read_response(conn))
27 return 1;
28
29 if (conn->resp != CLIS_OK) {
30 snmp_log(LOG_ERR, "command rejected: %u %s\n",
31 conn->resp, conn->base);
32 return 1;
33 }
34 return 0;
35}
36
37int
38varnish_ban(netsnmp_agent_request_info *reqinfo,
39 netsnmp_request_info *requests,
40 struct VSM_data *vd)
41{
42 int rc;
43 struct vcli_conn conn;
44 size_t len = requests->requestvb->val_len;
45 char *expr = malloc(len + 1);
46
47 if (!expr) {
48 snmp_log(LOG_ERR, "out of memory\n");
49 return SNMP_ERR_GENERR;
50 }
51 memcpy(expr, requests->requestvb->val.string, len);
52 expr[len] = 0;
53 DEBUGMSGTL(("vcli_mib", "ban %s\n", expr));
54 rc = vcli_connect(vd, &conn);
55 if (rc == SNMP_ERR_NOERROR) {
56 rc = send_ban_cmd(&conn, expr);
57 vcli_disconnect(&conn);
58 }
59 free(expr);
60 return rc ? SNMP_ERR_GENERR : SNMP_ERR_NOERROR;
61}
62
diff --git a/src/sha256.c b/src/sha256.c
new file mode 100644
index 0000000..bcb5f74
--- a/dev/null
+++ b/src/sha256.c
@@ -0,0 +1,570 @@
1/* sha256.c - Functions to compute SHA256 and SHA224 message digest of files or
2 memory blocks according to the NIST specification FIPS-180-2.
3
4 Copyright (C) 2005-2006, 2008-2013 Free Software Foundation, Inc.
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19/* Written by David Madore, considerably copypasting from
20 Scott G. Miller's sha1.c
21*/
22
23#include <config.h>
24
25#include "sha256.h"
26
27#include <stddef.h>
28#include <stdint.h>
29#include <stdlib.h>
30#include <string.h>
31
32#if USE_UNLOCKED_IO
33# include "unlocked-io.h"
34#endif
35
36#ifdef WORDS_BIGENDIAN
37# define SWAP(n) (n)
38#else
39# define SWAP(n) \
40 (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
41#endif
42
43#define BLOCKSIZE 32768
44#if BLOCKSIZE % 64 != 0
45# error "invalid BLOCKSIZE"
46#endif
47
48/* This array contains the bytes used to pad the buffer to the next
49 64-byte boundary. */
50static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
51
52
53/*
54 Takes a pointer to a 256 bit block of data (eight 32 bit ints) and
55 initializes it to the start constants of the SHA256 algorithm. This
56 must be called before using hash in the call to sha256_hash
57*/
58void
59sha256_init_ctx (struct sha256_ctx *ctx)
60{
61 ctx->state[0] = 0x6a09e667UL;
62 ctx->state[1] = 0xbb67ae85UL;
63 ctx->state[2] = 0x3c6ef372UL;
64 ctx->state[3] = 0xa54ff53aUL;
65 ctx->state[4] = 0x510e527fUL;
66 ctx->state[5] = 0x9b05688cUL;
67 ctx->state[6] = 0x1f83d9abUL;
68 ctx->state[7] = 0x5be0cd19UL;
69
70 ctx->total[0] = ctx->total[1] = 0;
71 ctx->buflen = 0;
72}
73
74void
75sha224_init_ctx (struct sha256_ctx *ctx)
76{
77 ctx->state[0] = 0xc1059ed8UL;
78 ctx->state[1] = 0x367cd507UL;
79 ctx->state[2] = 0x3070dd17UL;
80 ctx->state[3] = 0xf70e5939UL;
81 ctx->state[4] = 0xffc00b31UL;
82 ctx->state[5] = 0x68581511UL;
83 ctx->state[6] = 0x64f98fa7UL;
84 ctx->state[7] = 0xbefa4fa4UL;
85
86 ctx->total[0] = ctx->total[1] = 0;
87 ctx->buflen = 0;
88}
89
90/* Copy the value from v into the memory location pointed to by *cp,
91 If your architecture allows unaligned access this is equivalent to
92 * (uint32_t *) cp = v */
93static void
94set_uint32 (char *cp, uint32_t v)
95{
96 memcpy (cp, &v, sizeof v);
97}
98
99/* Put result from CTX in first 32 bytes following RESBUF. The result
100 must be in little endian byte order. */
101void *
102sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf)
103{
104 int i;
105 char *r = resbuf;
106
107 for (i = 0; i < 8; i++)
108 set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i]));
109
110 return resbuf;
111}
112
113void *
114sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf)
115{
116 int i;
117 char *r = resbuf;
118
119 for (i = 0; i < 7; i++)
120 set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i]));
121
122 return resbuf;
123}
124
125/* Process the remaining bytes in the internal buffer and the usual
126 prolog according to the standard and write the result to RESBUF. */
127static void
128sha256_conclude_ctx (struct sha256_ctx *ctx)
129{
130 /* Take yet unprocessed bytes into account. */
131 size_t bytes = ctx->buflen;
132 size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
133
134 /* Now count remaining bytes. */
135 ctx->total[0] += bytes;
136 if (ctx->total[0] < bytes)
137 ++ctx->total[1];
138
139 /* Put the 64-bit file length in *bits* at the end of the buffer.
140 Use set_uint32 rather than a simple assignment, to avoid risk of
141 unaligned access. */
142 set_uint32 ((char *) &ctx->buffer[size - 2],
143 SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)));
144 set_uint32 ((char *) &ctx->buffer[size - 1],
145 SWAP (ctx->total[0] << 3));
146
147 memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
148
149 /* Process last bytes. */
150 sha256_process_block (ctx->buffer, size * 4, ctx);
151}
152
153void *
154sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf)
155{
156 sha256_conclude_ctx (ctx);
157 return sha256_read_ctx (ctx, resbuf);
158}
159
160void *
161sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf)
162{
163 sha256_conclude_ctx (ctx);
164 return sha224_read_ctx (ctx, resbuf);
165}
166
167/* Compute SHA256 message digest for bytes read from STREAM. The
168 resulting message digest number will be written into the 32 bytes
169 beginning at RESBLOCK. */
170int
171sha256_stream (FILE *stream, void *resblock)
172{
173 struct sha256_ctx ctx;
174 size_t sum;
175
176 char *buffer = malloc (BLOCKSIZE + 72);
177 if (!buffer)
178 return 1;
179
180 /* Initialize the computation context. */
181 sha256_init_ctx (&ctx);
182
183 /* Iterate over full file contents. */
184 while (1)
185 {
186 /* We read the file in blocks of BLOCKSIZE bytes. One call of the
187 computation function processes the whole buffer so that with the
188 next round of the loop another block can be read. */
189 size_t n;
190 sum = 0;
191
192 /* Read block. Take care for partial reads. */
193 while (1)
194 {
195 n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
196
197 sum += n;
198
199 if (sum == BLOCKSIZE)
200 break;
201
202 if (n == 0)
203 {
204 /* Check for the error flag IFF N == 0, so that we don't
205 exit the loop after a partial read due to e.g., EAGAIN
206 or EWOULDBLOCK. */
207 if (ferror (stream))
208 {
209 free (buffer);
210 return 1;
211 }
212 goto process_partial_block;
213 }
214
215 /* We've read at least one byte, so ignore errors. But always
216 check for EOF, since feof may be true even though N > 0.
217 Otherwise, we could end up calling fread after EOF. */
218 if (feof (stream))
219 goto process_partial_block;
220 }
221
222 /* Process buffer with BLOCKSIZE bytes. Note that
223 BLOCKSIZE % 64 == 0
224 */
225 sha256_process_block (buffer, BLOCKSIZE, &ctx);
226 }
227
228 process_partial_block:;
229
230 /* Process any remaining bytes. */
231 if (sum > 0)
232 sha256_process_bytes (buffer, sum, &ctx);
233
234 /* Construct result in desired memory. */
235 sha256_finish_ctx (&ctx, resblock);
236 free (buffer);
237 return 0;
238}
239
240/* FIXME: Avoid code duplication */
241int
242sha224_stream (FILE *stream, void *resblock)
243{
244 struct sha256_ctx ctx;
245 size_t sum;
246
247 char *buffer = malloc (BLOCKSIZE + 72);
248 if (!buffer)
249 return 1;
250
251 /* Initialize the computation context. */
252 sha224_init_ctx (&ctx);
253
254 /* Iterate over full file contents. */
255 while (1)
256 {
257 /* We read the file in blocks of BLOCKSIZE bytes. One call of the
258 computation function processes the whole buffer so that with the
259 next round of the loop another block can be read. */
260 size_t n;
261 sum = 0;
262
263 /* Read block. Take care for partial reads. */
264 while (1)
265 {
266 n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);
267
268 sum += n;
269
270 if (sum == BLOCKSIZE)
271 break;
272
273 if (n == 0)
274 {
275 /* Check for the error flag IFF N == 0, so that we don't
276 exit the loop after a partial read due to e.g., EAGAIN
277 or EWOULDBLOCK. */
278 if (ferror (stream))
279 {
280 free (buffer);
281 return 1;
282 }
283 goto process_partial_block;
284 }
285
286 /* We've read at least one byte, so ignore errors. But always
287 check for EOF, since feof may be true even though N > 0.
288 Otherwise, we could end up calling fread after EOF. */
289 if (feof (stream))
290 goto process_partial_block;
291 }
292
293 /* Process buffer with BLOCKSIZE bytes. Note that
294 BLOCKSIZE % 64 == 0
295 */
296 sha256_process_block (buffer, BLOCKSIZE, &ctx);
297 }
298
299 process_partial_block:;
300
301 /* Process any remaining bytes. */
302 if (sum > 0)
303 sha256_process_bytes (buffer, sum, &ctx);
304
305 /* Construct result in desired memory. */
306 sha224_finish_ctx (&ctx, resblock);
307 free (buffer);
308 return 0;
309}
310
311/* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The
312 result is always in little endian byte order, so that a byte-wise
313 output yields to the wanted ASCII representation of the message
314 digest. */
315void *
316sha256_buffer (const char *buffer, size_t len, void *resblock)
317{
318 struct sha256_ctx ctx;
319
320 /* Initialize the computation context. */
321 sha256_init_ctx (&ctx);
322
323 /* Process whole buffer but last len % 64 bytes. */
324 sha256_process_bytes (buffer, len, &ctx);
325
326 /* Put result in desired memory area. */
327 return sha256_finish_ctx (&ctx, resblock);
328}
329
330void *
331sha224_buffer (const char *buffer, size_t len, void *resblock)
332{
333 struct sha256_ctx ctx;
334
335 /* Initialize the computation context. */
336 sha224_init_ctx (&ctx);
337
338 /* Process whole buffer but last len % 64 bytes. */
339 sha256_process_bytes (buffer, len, &ctx);
340
341 /* Put result in desired memory area. */
342 return sha224_finish_ctx (&ctx, resblock);
343}
344
345void
346sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx)
347{
348 /* When we already have some bits in our internal buffer concatenate
349 both inputs first. */
350 if (ctx->buflen != 0)
351 {
352 size_t left_over = ctx->buflen;
353 size_t add = 128 - left_over > len ? len : 128 - left_over;
354
355 memcpy (&((char *) ctx->buffer)[left_over], buffer, add);
356 ctx->buflen += add;
357
358 if (ctx->buflen > 64)
359 {
360 sha256_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
361
362 ctx->buflen &= 63;
363 /* The regions in the following copy operation cannot overlap. */
364 memcpy (ctx->buffer,
365 &((char *) ctx->buffer)[(left_over + add) & ~63],
366 ctx->buflen);
367 }
368
369 buffer = (const char *) buffer + add;
370 len -= add;
371 }
372
373 /* Process available complete blocks. */
374 if (len >= 64)
375 {
376#if !_STRING_ARCH_unaligned
377# define alignof(type) offsetof (struct { char c; type x; }, x)
378# define UNALIGNED_P(p) ((uintptr_t) (p) % alignof (uint32_t) != 0)
379 if (UNALIGNED_P (buffer))
380 while (len > 64)
381 {
382 sha256_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
383 buffer = (const char *) buffer + 64;
384 len -= 64;
385 }
386 else
387#endif
388 {
389 sha256_process_block (buffer, len & ~63, ctx);
390 buffer = (const char *) buffer + (len & ~63);
391 len &= 63;
392 }
393 }
394
395 /* Move remaining bytes in internal buffer. */
396 if (len > 0)
397 {
398 size_t left_over = ctx->buflen;
399
400 memcpy (&((char *) ctx->buffer)[left_over], buffer, len);
401 left_over += len;
402 if (left_over >= 64)
403 {
404 sha256_process_block (ctx->buffer, 64, ctx);
405 left_over -= 64;
406 memcpy (ctx->buffer, &ctx->buffer[16], left_over);
407 }
408 ctx->buflen = left_over;
409 }
410}
411
412/* --- Code below is the primary difference between sha1.c and sha256.c --- */
413
414/* SHA256 round constants */
415#define K(I) sha256_round_constants[I]
416static const uint32_t sha256_round_constants[64] = {
417 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
418 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
419 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
420 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
421 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
422 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
423 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
424 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
425 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
426 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
427 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
428 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
429 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
430 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
431 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
432 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL,
433};
434
435/* Round functions. */
436#define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) )
437#define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) )
438
439/* Process LEN bytes of BUFFER, accumulating context into CTX.
440 It is assumed that LEN % 64 == 0.
441 Most of this code comes from GnuPG's cipher/sha1.c. */
442
443void
444sha256_process_block (const void *buffer, size_t len, struct sha256_ctx *ctx)
445{
446 const uint32_t *words = buffer;
447 size_t nwords = len / sizeof (uint32_t);
448 const uint32_t *endp = words + nwords;
449 uint32_t x[16];
450 uint32_t a = ctx->state[0];
451 uint32_t b = ctx->state[1];
452 uint32_t c = ctx->state[2];
453 uint32_t d = ctx->state[3];
454 uint32_t e = ctx->state[4];
455 uint32_t f = ctx->state[5];
456 uint32_t g = ctx->state[6];
457 uint32_t h = ctx->state[7];
458 uint32_t lolen = len;
459
460 /* First increment the byte count. FIPS PUB 180-2 specifies the possible
461 length of the file up to 2^64 bits. Here we only compute the
462 number of bytes. Do a double word increment. */
463 ctx->total[0] += lolen;
464 ctx->total[1] += (len >> 31 >> 1) + (ctx->total[0] < lolen);
465
466#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
467#define S0(x) (rol(x,25)^rol(x,14)^(x>>3))
468#define S1(x) (rol(x,15)^rol(x,13)^(x>>10))
469#define SS0(x) (rol(x,30)^rol(x,19)^rol(x,10))
470#define SS1(x) (rol(x,26)^rol(x,21)^rol(x,7))
471
472#define M(I) ( tm = S1(x[(I-2)&0x0f]) + x[(I-7)&0x0f] \
473 + S0(x[(I-15)&0x0f]) + x[I&0x0f] \
474 , x[I&0x0f] = tm )
475
476#define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \
477 t1 = H + SS1(E) \
478 + F1(E,F,G) \
479 + K \
480 + M; \
481 D += t1; H = t0 + t1; \
482 } while(0)
483
484 while (words < endp)
485 {
486 uint32_t tm;
487 uint32_t t0, t1;
488 int t;
489 /* FIXME: see sha1.c for a better implementation. */
490 for (t = 0; t < 16; t++)
491 {
492 x[t] = SWAP (*words);
493 words++;
494 }
495
496 R( a, b, c, d, e, f, g, h, K( 0), x[ 0] );
497 R( h, a, b, c, d, e, f, g, K( 1), x[ 1] );
498 R( g, h, a, b, c, d, e, f, K( 2), x[ 2] );
499 R( f, g, h, a, b, c, d, e, K( 3), x[ 3] );
500 R( e, f, g, h, a, b, c, d, K( 4), x[ 4] );
501 R( d, e, f, g, h, a, b, c, K( 5), x[ 5] );
502 R( c, d, e, f, g, h, a, b, K( 6), x[ 6] );
503 R( b, c, d, e, f, g, h, a, K( 7), x[ 7] );
504 R( a, b, c, d, e, f, g, h, K( 8), x[ 8] );
505 R( h, a, b, c, d, e, f, g, K( 9), x[ 9] );
506 R( g, h, a, b, c, d, e, f, K(10), x[10] );
507 R( f, g, h, a, b, c, d, e, K(11), x[11] );
508 R( e, f, g, h, a, b, c, d, K(12), x[12] );
509 R( d, e, f, g, h, a, b, c, K(13), x[13] );
510 R( c, d, e, f, g, h, a, b, K(14), x[14] );
511 R( b, c, d, e, f, g, h, a, K(15), x[15] );
512 R( a, b, c, d, e, f, g, h, K(16), M(16) );
513 R( h, a, b, c, d, e, f, g, K(17), M(17) );
514 R( g, h, a, b, c, d, e, f, K(18), M(18) );
515 R( f, g, h, a, b, c, d, e, K(19), M(19) );
516 R( e, f, g, h, a, b, c, d, K(20), M(20) );
517 R( d, e, f, g, h, a, b, c, K(21), M(21) );
518 R( c, d, e, f, g, h, a, b, K(22), M(22) );
519 R( b, c, d, e, f, g, h, a, K(23), M(23) );
520 R( a, b, c, d, e, f, g, h, K(24), M(24) );
521 R( h, a, b, c, d, e, f, g, K(25), M(25) );
522 R( g, h, a, b, c, d, e, f, K(26), M(26) );
523 R( f, g, h, a, b, c, d, e, K(27), M(27) );
524 R( e, f, g, h, a, b, c, d, K(28), M(28) );
525 R( d, e, f, g, h, a, b, c, K(29), M(29) );
526 R( c, d, e, f, g, h, a, b, K(30), M(30) );
527 R( b, c, d, e, f, g, h, a, K(31), M(31) );
528 R( a, b, c, d, e, f, g, h, K(32), M(32) );
529 R( h, a, b, c, d, e, f, g, K(33), M(33) );
530 R( g, h, a, b, c, d, e, f, K(34), M(34) );
531 R( f, g, h, a, b, c, d, e, K(35), M(35) );
532 R( e, f, g, h, a, b, c, d, K(36), M(36) );
533 R( d, e, f, g, h, a, b, c, K(37), M(37) );
534 R( c, d, e, f, g, h, a, b, K(38), M(38) );
535 R( b, c, d, e, f, g, h, a, K(39), M(39) );
536 R( a, b, c, d, e, f, g, h, K(40), M(40) );
537 R( h, a, b, c, d, e, f, g, K(41), M(41) );
538 R( g, h, a, b, c, d, e, f, K(42), M(42) );
539 R( f, g, h, a, b, c, d, e, K(43), M(43) );
540 R( e, f, g, h, a, b, c, d, K(44), M(44) );
541 R( d, e, f, g, h, a, b, c, K(45), M(45) );
542 R( c, d, e, f, g, h, a, b, K(46), M(46) );
543 R( b, c, d, e, f, g, h, a, K(47), M(47) );
544 R( a, b, c, d, e, f, g, h, K(48), M(48) );
545 R( h, a, b, c, d, e, f, g, K(49), M(49) );
546 R( g, h, a, b, c, d, e, f, K(50), M(50) );
547 R( f, g, h, a, b, c, d, e, K(51), M(51) );
548 R( e, f, g, h, a, b, c, d, K(52), M(52) );
549 R( d, e, f, g, h, a, b, c, K(53), M(53) );
550 R( c, d, e, f, g, h, a, b, K(54), M(54) );
551 R( b, c, d, e, f, g, h, a, K(55), M(55) );
552 R( a, b, c, d, e, f, g, h, K(56), M(56) );
553 R( h, a, b, c, d, e, f, g, K(57), M(57) );
554 R( g, h, a, b, c, d, e, f, K(58), M(58) );
555 R( f, g, h, a, b, c, d, e, K(59), M(59) );
556 R( e, f, g, h, a, b, c, d, K(60), M(60) );
557 R( d, e, f, g, h, a, b, c, K(61), M(61) );
558 R( c, d, e, f, g, h, a, b, K(62), M(62) );
559 R( b, c, d, e, f, g, h, a, K(63), M(63) );
560
561 a = ctx->state[0] += a;
562 b = ctx->state[1] += b;
563 c = ctx->state[2] += c;
564 d = ctx->state[3] += d;
565 e = ctx->state[4] += e;
566 f = ctx->state[5] += f;
567 g = ctx->state[6] += g;
568 h = ctx->state[7] += h;
569 }
570}
diff --git a/src/sha256.h b/src/sha256.h
new file mode 100644
index 0000000..44060a7
--- a/dev/null
+++ b/src/sha256.h
@@ -0,0 +1,91 @@
1/* Declarations of functions and data types used for SHA256 and SHA224 sum
2 library functions.
3 Copyright (C) 2005-2006, 2008-2013 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
18#ifndef ECLAT_SHA256_H
19# define ECLAT_SHA256_H 1
20
21# include <stdio.h>
22# include <stdint.h>
23
24# ifdef __cplusplus
25extern "C" {
26# endif
27
28/* Structure to save state of computation between the single steps. */
29struct sha256_ctx
30{
31 uint32_t state[8];
32
33 uint32_t total[2];
34 size_t buflen;
35 uint32_t buffer[32];
36};
37
38enum { SHA224_DIGEST_SIZE = 224 / 8 };
39enum { SHA256_DIGEST_SIZE = 256 / 8 };
40
41/* Initialize structure containing state of computation. */
42extern void sha256_init_ctx (struct sha256_ctx *ctx);
43extern void sha224_init_ctx (struct sha256_ctx *ctx);
44
45/* Starting with the result of former calls of this function (or the
46 initialization function update the context for the next LEN bytes
47 starting at BUFFER.
48 It is necessary that LEN is a multiple of 64!!! */
49extern void sha256_process_block (const void *buffer, size_t len,
50 struct sha256_ctx *ctx);
51
52/* Starting with the result of former calls of this function (or the
53 initialization function update the context for the next LEN bytes
54 starting at BUFFER.
55 It is NOT required that LEN is a multiple of 64. */
56extern void sha256_process_bytes (const void *buffer, size_t len,
57 struct sha256_ctx *ctx);
58
59/* Process the remaining bytes in the buffer and put result from CTX
60 in first 32 (28) bytes following RESBUF. The result is always in little
61 endian byte order, so that a byte-wise output yields to the wanted
62 ASCII representation of the message digest. */
63extern void *sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf);
64extern void *sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf);
65
66
67/* Put result from CTX in first 32 (28) bytes following RESBUF. The result is
68 always in little endian byte order, so that a byte-wise output yields
69 to the wanted ASCII representation of the message digest. */
70extern void *sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf);
71extern void *sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf);
72
73
74/* Compute SHA256 (SHA224) message digest for bytes read from STREAM. The
75 resulting message digest number will be written into the 32 (28) bytes
76 beginning at RESBLOCK. */
77extern int sha256_stream (FILE *stream, void *resblock);
78extern int sha224_stream (FILE *stream, void *resblock);
79
80/* Compute SHA256 (SHA224) message digest for LEN bytes beginning at BUFFER. The
81 result is always in little endian byte order, so that a byte-wise
82 output yields to the wanted ASCII representation of the message
83 digest. */
84extern void *sha256_buffer (const char *buffer, size_t len, void *resblock);
85extern void *sha224_buffer (const char *buffer, size_t len, void *resblock);
86
87# ifdef __cplusplus
88}
89# endif
90
91#endif
diff --git a/src/varnish_mib.h b/src/varnish_mib.h
new file mode 100644
index 0000000..31e3de1
--- a/dev/null
+++ b/src/varnish_mib.h
@@ -0,0 +1,52 @@
1/* This file is part of varnish-mib -*- c -*-
2 Copyright (C) 2014 Sergey Poznyakoff
3
4 Varnish-mib is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 Varnish-mib is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with varnish-mib. If not, see <http://www.gnu.org/licenses/>.
16*/
17#include <config.h>
18#include <stdlib.h>
19#include <stdint.h>
20
21#include <vapi/vsc.h>
22#include <vapi/vsm.h>
23#include <vcli.h>
24
25#include <net-snmp/net-snmp-config.h>
26#include <net-snmp/net-snmp-includes.h>
27#include <net-snmp/agent/net-snmp-agent-includes.h>
28
29typedef struct vcli_conn {
30 int fd;
31 char *secret;
32 int resp;
33 char *base;
34 size_t bufmax;
35 size_t bufsize;
36} vcli_conn_t;
37
38int vcli_write(vcli_conn_t *conn);
39int vcli_read_response(vcli_conn_t *conn);
40int vcli_vasprintf(vcli_conn_t *conn, const char *fmt, va_list ap);
41int vcli_asprintf(vcli_conn_t *conn, const char *fmt, ...);
42void vcli_disconnect(vcli_conn_t *conn);
43int vcli_connect(struct VSM_data *vd, vcli_conn_t *conn);
44
45
46int varnish_auth_response(const char *file, const char *challenge,
47 char response[CLI_AUTH_RESPONSE_LEN + 1]);
48
49int varnish_ban(netsnmp_agent_request_info *reqinfo,
50 netsnmp_request_info *requests,
51 struct VSM_data *vd);
52
diff --git a/src/varnish_mib.mib2c b/src/varnish_mib.mib2c
index af56a0e..8535b0d 100644
--- a/src/varnish_mib.mib2c
+++ b/src/varnish_mib.mib2c
@@ -26,16 +26,7 @@
26@open ${name}@ 26@open ${name}@
27/* THIS FILE IS GENERATED AUTOMATICALLY. PLEASE DO NOT EDIT. */ 27/* THIS FILE IS GENERATED AUTOMATICALLY. PLEASE DO NOT EDIT. */
28 28
29#include <config.h> 29#include "varnish_mib.h"
30#include <stdlib.h>
31#include <stdint.h>
32
33#include <vapi/vsc.h>
34#include <vapi/vsm.h>
35
36#include <net-snmp/net-snmp-config.h>
37#include <net-snmp/net-snmp-includes.h>
38#include <net-snmp/agent/net-snmp-agent-includes.h>
39 30
40static struct VSM_data *vd; 31static struct VSM_data *vd;
41 32
@@ -58,25 +49,27 @@ varnish_snmp_deinit(void)
58$vars{'varnish_translate'} = sub { 49$vars{'varnish_translate'} = sub {
59 my $name = shift; 50 my $name = shift;
60 my %trans = ( 51 my %trans = (
61 clientAcceptedConnections => 'sess_conn', 52 clientAcceptedConnections => [ 'MAIN', 'sess_conn' ],
62 clientRequestsReceived => 'client_req', 53 clientRequestsReceived => [ 'MAIN', 'client_req' ],
63 clientCacheHits => 'cache_hit', 54 clientCacheHits => [ 'MAIN', 'cache_hit' ],
64 clientCacheHitsPass => 'cache_hitpass', 55 clientCacheHitsPass => [ 'MAIN', 'cache_hitpass' ],
65 clientCacheMisses => 'cache_miss', 56 clientCacheMisses => [ 'MAIN', 'cache_miss' ],
66 backendConnSuccess => 'backend_conn', 57 clientBan => [ 'STRING', '',
67 backendConnNotAttempted => 'backend_unhealthy', 58 { varnish_set_action => 'varnish_ban' } ],
68 backendConnToMany => 'backend_busy ', 59 backendConnSuccess => [ 'MAIN', 'backend_conn' ],
69 backendConnFailures => 'backend_fail', 60 backendConnNotAttempted => [ 'MAIN', 'backend_unhealthy' ],
70 backendConnReuses => 'backend_reuse', 61 backendConnToMany => [ 'MAIN', 'backend_busy' ],
71 backendConnRecycled => 'backend_recycle', 62 backendConnFailures => [ 'MAIN', 'backend_fail' ],
72 backendConnUnused => 'backend_toolate', 63 backendConnReuses => [ 'MAIN', 'backend_reuse' ],
73 totalSessions => 's_sess', 64 backendConnRecycled => [ 'MAIN', 'backend_recycle' ],
74 totalRequests => 's_req ', 65 backendConnUnused => [ 'MAIN', 'backend_toolate' ],
75 totalPipe => 's_pipe', 66 totalSessions => [ 'MAIN', 's_sess' ],
76 totalPass => 's_pass', 67 totalRequests => [ 'MAIN', 's_req' ],
77 totalFetch => 's_fetch', 68 totalPipe => [ 'MAIN', 's_pipe' ],
78 totalHeaderBytes => 's_req_hdrbytes', 69 totalPass => [ 'MAIN', 's_pass' ],
79 totalBodyBytes => 's_req_bodybytes' 70 totalFetch => [ 'MAIN', 's_fetch' ],
71 totalHeaderBytes => [ 'MAIN', 's_req_hdrbytes' ],
72 totalBodyBytes => [ 'MAIN', 's_req_bodybytes' ]
80 ); 73 );
81 74
82 my $r = $trans{$name}; 75 my $r = $trans{$name};
@@ -84,7 +77,16 @@ $vars{'varnish_translate'} = sub {
84 print STDERR "no translation for $name!\n"; 77 print STDERR "no translation for $name!\n";
85 exit(1); 78 exit(1);
86 } 79 }
87 $vars{'varnish_member'} = $r; 80
81 $vars{'varnish_type'} = $r->[0];
82 $vars{'varnish_member'} = $r->[1];
83 my $setkw = qw(varnish_set_reserve2 varnish_set_free varnish_set_action
84 varnish_set_commit varnish_set_undo);
85 if ($#{$r} == 2) {
86 @vars{keys %{$r->[2]}} = values %{$r->[2]};
87 } else {
88 delete $vars{$setkw};
89 }
88 return 0; 90 return 0;
89}; 91};
90 92
@@ -110,31 +112,106 @@ handle_$i(netsnmp_mib_handler *handler,
110 netsnmp_agent_request_info *reqinfo, 112 netsnmp_agent_request_info *reqinfo,
111 netsnmp_request_info *requests) 113 netsnmp_request_info *requests)
112{ 114{
113 uint32_t val; 115 @if $i.settable@
116 int ret;
117 @end@
114 118
115 @startperl@ 119 @startperl@
116 &{$vars{'varnish_translate'}}($vars{'i'}); 120 &{$vars{'varnish_translate'}}($vars{'i'});
117 @endperl@ 121 @endperl@
118 if (reqinfo->mode == MODE_GET) { 122
119 struct VSC_C_main const *st; 123 if (VSM_Abandoned(vd)) {
120 124 DEBUGMSGTL(("$modulename", "reopening vd\n"));
121 if (VSM_Abandoned(vd)) { 125 VSM_Close(vd);
122 VSM_Close(vd); 126 VSM_Open(vd);
123 VSM_Open(vd); 127 }
124 } 128
125 129 switch(reqinfo->mode) {
126 st = VSC_Main(vd, NULL); 130 case MODE_GET:
131 @if $varnish_type eq 'MAIN'@
132 {
133 struct VSC_C_main const *st = VSC_Main(vd, NULL);
127 if (!st) 134 if (!st)
128 return SNMP_ERR_NOSUCHNAME; 135 return SNMP_ERR_NOSUCHNAME;
129 snmp_set_var_typed_value(requests->requestvb, $i.type, 136 snmp_set_var_typed_value(requests->requestvb, $i.type,
130 &st->$varnish_member, 137 &st->$varnish_member,
131 sizeof(st->$varnish_member)); 138 sizeof(st->$varnish_member));
132 } else {
133 snmp_log(LOG_ERR, "unknown mode (%d) in handle_${i}\n",
134 reqinfo->mode );
135 return SNMP_ERR_GENERR;
136 } 139 }
140 @elsif $varnish_type eq 'STRING'@
141 {
142 const char *s = "$varnish_member";
143 snmp_set_var_typed_value(requests->requestvb, $i.type,
144 s, strlen(s));
145 }
146 @else@
147 @printf "unrecognized type %s for %s" $varnish_type $i@
148 @end@
149 break;
150
151 @if $i.settable@
152 /*
153 * SET REQUEST
154 *
155 * multiple states in the transaction. See:
156 * http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
157 */
158 case MODE_SET_RESERVE1:
159 /* or you could use netsnmp_check_vb_type_and_size instead */
160 ret = netsnmp_check_vb_type(requests->requestvb, $i.type);
161 if (ret != SNMP_ERR_NOERROR)
162 netsnmp_set_request_error(reqinfo, requests, ret);
163 break;
164
165 case MODE_SET_RESERVE2:
166 @if $varnish_set_reserve2 ne ''@
167 if ($varnish_set_reserve2 (reqinfo, requests, vd)) {
168 netsnmp_set_request_error(reqinfo, requests,
169 SNMP_ERR_RESOURCEUNAVAILABLE);
170 }
171 @end@
172 break;
173
174 case MODE_SET_FREE:
175 @if $varnish_set_free ne ''@
176 /* XXX: free resources allocated in RESERVE1 and/or
177 RESERVE2. Something failed somewhere, and the states
178 below won't be called. */
179 $varnish_set_free(reqinfo, requests, vd);
180 @end@
181 break;
182
183 case MODE_SET_ACTION:
184 @if $varnish_set_action ne ''@
185 /* XXX: perform the value change here */
186 ret = $varnish_set_action(reqinfo, requests, vd);
187 if (ret != SNMP_ERR_NOERROR)
188 netsnmp_set_request_error(reqinfo, requests, ret);
189 @end@
190 break;
191
192 case MODE_SET_COMMIT:
193 @if $varnish_set_commit ne ''@
194 /* XXX: delete temporary storage */
195 if ($varnish_set_commit(reqinfo, requests, vd))
196 netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_COMMITFAILED);
197 @end@
198 break;
199
200 case MODE_SET_UNDO:
201 @if $varnish_set_undo ne ''@
202 /* XXX: UNDO and return to previous value for the object */
203 if ($varnish_set_undo(reqinfo, requests, vd))
204 netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_UNDOFAILED);
205 @end@
206 break;
207 @end@
137 208
209 default:
210 /* we should never get here, so this is a really bad error */
211 snmp_log(LOG_ERR, "unknown mode (%d) in handle_${i}\n", reqinfo->mode );
212 return SNMP_ERR_GENERR;
213 }
214
138 return SNMP_ERR_NOERROR; 215 return SNMP_ERR_NOERROR;
139} 216}
140@end@ 217@end@
@@ -153,7 +230,13 @@ init_$modulename(void)
153 netsnmp_register_scalar( 230 netsnmp_register_scalar(
154 netsnmp_create_handler_registration("$i", handle_$i, 231 netsnmp_create_handler_registration("$i", handle_$i,
155 ${i}_oid, OID_LENGTH(${i}_oid), 232 ${i}_oid, OID_LENGTH(${i}_oid),
156 HANDLER_CAN_RONLY)); 233 @if !$i.settable@
234 HANDLER_CAN_RONLY
235 @end@
236 @if $i.settable@
237 HANDLER_CAN_RWRITE
238 @end@
239 ));
157 @end@ 240 @end@
158 varnish_snmp_init(); 241 varnish_snmp_init();
159} 242}
diff --git a/src/vcli.c b/src/vcli.c
new file mode 100644
index 0000000..aaa0933
--- a/dev/null
+++ b/src/vcli.c
@@ -0,0 +1,499 @@
1/* This file is part of varnish-mib -*- c -*-
2 Copyright (C) 2014 Sergey Poznyakoff
3
4 Varnish-mib is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 Varnish-mib is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with varnish-mib. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "varnish_mib.h"
19#include <sys/types.h>
20#include <sys/socket.h>
21#include <sys/time.h>
22#include <sys/ioctl.h>
23#include <netinet/in.h>
24#include <netdb.h>
25#include <arpa/inet.h>
26#include <errno.h>
27
28#define ISSPACE(c) ((c)==' '||(c)=='\t'||(c)=='\n')
29
30unsigned long vcli_timeout = 500;
31
32#define VCLI_INIT_ALLOC 16
33
34static int
35vcli_alloc(struct vcli_conn *conn, size_t size)
36{
37 char *p;
38
39 if (size < conn->bufmax)
40 return 0;
41 p = realloc(conn->base, size);
42 if (!p) {
43 snmp_log(LOG_ERR, "out of memory\n");
44 return -1;
45 }
46 conn->base = p;
47 conn->bufmax = size;
48 return 0;
49}
50
51static int
52vcli_extra_size(struct vcli_conn *conn, size_t incr)
53{
54 if (incr + conn->bufsize > conn->bufmax) {
55 size_t size;
56 if (conn->bufmax == 0)
57 size = incr > VCLI_INIT_ALLOC
58 ? incr
59 : VCLI_INIT_ALLOC;
60 else {
61 for (size = conn->bufmax; size < conn->bufsize + incr;
62 size *= 2)
63 if (size <= conn->bufmax) {
64 snmp_log(LOG_ERR, "out of memory\n");
65 return -1;
66 }
67 }
68 return vcli_alloc(conn, size);
69 }
70 return 0;
71}
72
73static int
74vcli_read(struct vcli_conn *conn, size_t size)
75{
76 fd_set rd;
77 time_t start;
78 struct timeval tv;
79 long ttl;
80 int ret = 0;
81 int rc;
82
83 ++size;
84 rc = vcli_alloc(conn, size + 1);
85 if (rc)
86 return SNMP_ERR_GENERR;
87
88 conn->bufsize = 0;
89 time(&start);
90 while (size) {
91 FD_ZERO(&rd);
92 FD_SET(conn->fd, &rd);
93
94 ttl = vcli_timeout - (time(NULL) - start);
95 if (ttl <= 0) {
96 snmp_log(LOG_ERR, "timed out reading from varnish\n");
97 ret = -1;
98 break;
99 }
100
101 tv.tv_sec = ttl;
102 tv.tv_usec = 0;
103 rc = select(conn->fd + 1, &rd, NULL, NULL, &tv);
104 if (rc < 0) {
105 if (errno == EINTR || errno == EAGAIN)
106 continue;
107 snmp_log(LOG_ERR, "select: %s\n", strerror(errno));
108 ret = -1;
109 break;
110 }
111
112 if (FD_ISSET(conn->fd, &rd)) {
113 int n;
114
115 if (ioctl(conn->fd, FIONREAD, &n) < 0) {
116 snmp_log(LOG_ERR, "ioctl: %s\n",
117 strerror(errno));
118 ret = -1;
119 break;
120 }
121 if (n > size)
122 n = size;
123 rc = read(conn->fd, conn->base + conn->bufsize, n);
124 if (rc > 0) {
125 conn->bufsize += rc;
126 size -= rc;
127 } else if (rc == 0
128 || errno == EINTR || errno == EAGAIN) {
129 continue;
130 } else {
131 snmp_log(LOG_ERR, "read: %s\n",
132 strerror(errno));
133 ret = -1;
134 break;
135 }
136 }
137 }
138
139 if (ret == 0) {
140 if (conn->bufsize == 0)
141 ret = -1;
142 conn->base[conn->bufsize] = 0;
143 DEBUGMSGTL(("vcli_mib", "<<varnish: %s\n", conn->base));
144 }
145
146 return ret;
147}
148
149static int
150vcli_getline(struct vcli_conn *conn)
151{
152 fd_set rd;
153 time_t start;
154 struct timeval tv;
155 long ttl;
156 int ret = 0;
157 int rc;
158
159 conn->bufsize = 0;
160 time(&start);
161 while (1) {
162 FD_ZERO(&rd);
163 FD_SET(conn->fd, &rd);
164
165 ttl = vcli_timeout - (time(NULL) - start);
166 if (ttl <= 0) {
167 snmp_log(LOG_ERR, "timed out reading from varnish\n");
168 ret = -1;
169 break;
170 }
171
172 tv.tv_sec = ttl;
173 tv.tv_usec = 0;
174 rc = select(conn->fd + 1, &rd, NULL, NULL, &tv);
175 if (rc < 0) {
176 if (errno == EINTR || errno == EAGAIN)
177 continue;
178 snmp_log(LOG_ERR, "select: %s\n", strerror(errno));
179 ret = -1;
180 break;
181 }
182
183 if (FD_ISSET(conn->fd, &rd)) {
184 char c;
185
186 rc = read(conn->fd, &c, 1);
187 if (rc == 1) {
188 if (vcli_extra_size(conn, 1)) {
189 ret = -1;
190 break;
191 }
192 conn->base[conn->bufsize++] = c;
193 if (c == '\n')
194 break;
195 } else if (rc == 0
196 || errno == EINTR || errno == EAGAIN) {
197 continue;
198 } else {
199 snmp_log(LOG_ERR, "read: %s\n",
200 strerror(errno));
201 ret = -1;
202 break;
203 }
204 }
205 }
206
207 if (ret == 0) {
208 if (conn->bufsize == 0)
209 ret = -1;
210 else if (conn->base[conn->bufsize-1] == '\n') {
211 conn->bufsize--;
212 if (conn->base[conn->bufsize-1] == '\r')
213 conn->bufsize--;
214 }
215 conn->base[conn->bufsize] = 0;
216 }
217
218 return ret;
219}
220
221int
222vcli_write(struct vcli_conn *conn)
223{
224 size_t size;
225
226 DEBUGMSGTL(("vcli_mib", ">>varnish: %s\n", conn->base));
227 for (size = 0; size < conn->bufsize; ) {
228 int n = write(conn->fd, conn->base + size,
229 conn->bufsize - size);
230 if (n < 0) {
231 snmp_log(LOG_ERR, "write error: %s\n",
232 strerror(errno));
233 return -1;
234 }
235 size += n;
236 }
237 return 0;
238}
239
240int
241vcli_read_response(struct vcli_conn *conn)
242{
243 char *p;
244 unsigned long n;
245
246 if (vcli_getline(conn)) {
247 vcli_disconnect(conn);
248 return SNMP_ERR_GENERR;
249 }
250
251 n = strtoul(conn->base, &p, 10);
252 conn->resp = n;
253 if (!ISSPACE(*p)) {
254 snmp_log(LOG_ERR, "unrecognized response from Varnish: %s\n",
255 conn->base);
256 return SNMP_ERR_GENERR;
257 }
258 while (*p && ISSPACE(*p))
259 ++p;
260 n = strtoul(p, &p, 10);
261 if (n > 0)
262 return vcli_read(conn, n);
263 return 0;
264}
265
266int
267vcli_vasprintf(struct vcli_conn *conn, const char *fmt, va_list ap)
268{
269 int rc = 0;
270
271 rc = vcli_alloc(conn, VCLI_INIT_ALLOC);
272 if (rc)
273 return -1;
274
275 for (;;) {
276 va_list aq;
277 ssize_t n;
278
279 va_copy(aq, ap);
280 n = vsnprintf(conn->base, conn->bufmax, fmt, aq);
281 va_end(aq);
282 if (n < 0 || n >= conn->bufmax ||
283 !memchr(conn->base, '\0', n + 1)) {
284 size_t newlen = conn->bufmax * 2;
285 if (newlen < conn->bufmax) {
286 snmp_log(LOG_ERR, "out of memory\n");
287 rc = -1;
288 break;
289 }
290 rc = vcli_alloc(conn, newlen);
291 if (rc)
292 break;
293 } else {
294 conn->bufsize = n;
295 break;
296 }
297 }
298
299 return rc;
300}
301
302int
303vcli_asprintf(struct vcli_conn *conn, const char *fmt, ...)
304{
305 int rc;
306 va_list ap;
307
308 va_start(ap, fmt);
309 rc = vcli_vasprintf(conn, fmt, ap);
310 va_end(ap);
311 return rc;
312}
313
314
315static int
316open_socket(struct sockaddr_in *sa, const char *connstr)
317{
318 int fd = socket(sa->sin_family, SOCK_STREAM, 0);
319 struct timeval start, connect_tv;
320
321 if (fd == -1) {
322 snmp_log(LOG_ERR, "socket: %s\n", strerror(errno));
323 return -1;
324 }
325
326 connect_tv.tv_sec = vcli_timeout;
327 connect_tv.tv_usec = 0;
328
329 gettimeofday(&start, NULL);
330 for (;;) {
331 int rc = connect(fd, sa, sizeof(*sa));
332 if (rc == 0)
333 break;
334 else if (errno == ECONNREFUSED) {
335 struct timeval tv, now;
336 fd_set rset, wset, xset;
337
338 gettimeofday(&now, NULL);
339 timersub(&now, &start, &tv);
340
341 if (timercmp(&tv, &connect_tv, < )) {
342 FD_ZERO(&rset);
343 FD_SET(fd, &rset);
344 FD_ZERO(&wset);
345 FD_SET(fd, &wset);
346 FD_ZERO(&xset);
347 FD_SET(fd, &xset);
348 select(fd + 1, &rset, &wset, &xset, &tv);
349 continue;
350 }
351 }
352
353 snmp_log(LOG_ERR, "cannot connect to %s: %s\n",
354 connstr, strerror(errno));
355 close(fd);
356 return -1;
357 }
358
359 return fd;
360}
361
362void
363vcli_disconnect(struct vcli_conn *conn)
364{
365 close(conn->fd);
366 free(conn->base);
367 free(conn->secret);
368 memset(conn, 0, sizeof(*conn));
369}
370
371static int
372vcli_handshake(struct vcli_conn *conn)
373{
374 if (vcli_read_response(conn))
375 return 1;
376
377 if (conn->resp == CLIS_AUTH) {
378 char buf[CLI_AUTH_RESPONSE_LEN + 1];
379 char *p = strchr(conn->base, '\n');
380
381 if (!p) {
382 snmp_log(LOG_ERR,
383 "unrecognized response from Varnish: %s\n",
384 conn->base);
385 return SNMP_ERR_GENERR;
386 }
387 *p = 0;
388 if (varnish_auth_response(conn->secret, conn->base, buf))
389 return 1;
390
391 if (vcli_asprintf(conn, "auth %s\n", buf) ||
392 vcli_write(conn))
393 return 1;
394
395 if (vcli_read_response(conn))
396 return 1;
397 }
398
399 if (conn->resp != CLIS_OK) {
400 snmp_log(LOG_ERR, "Varnish connection rejected: %u %s\n",
401 conn->resp, conn->base);
402 return 1;
403 }
404
405 if (vcli_asprintf(conn, "ping\n") || vcli_write(conn))
406 return 1;
407
408 if (vcli_read_response(conn))
409 return 1;
410
411 if (conn->resp != CLIS_OK || strstr(conn->base, "PONG") == NULL) {
412 snmp_log(LOG_ERR, "expected PONG, but got %s\n",
413 conn->base);
414 return 1;
415 }
416
417 return 0;
418}
419
420int
421vcli_connect(struct VSM_data *vd, struct vcli_conn *conn)
422{
423 struct VSM_fantom vt;
424 struct sockaddr_in vcli_sa;
425 char *s, *portstr, *p;
426 unsigned long n;
427 short pn;
428 struct hostent *hp;
429
430 memset(conn, 0, sizeof(*conn));
431
432 if (!VSM_Get(vd, &vt, "Arg", "-T", "")) {
433 snmp_log(LOG_ERR, "no -T arg in shared memory\n");
434 return SNMP_ERR_GENERR;
435 }
436 DEBUGMSGTL(("vcli_mib", "-T '%s'\n", vt.b));
437
438 s = strdup(vt.b);
439 if (!s) {
440 snmp_log(LOG_ERR, "out of memory\n");
441 return SNMP_ERR_GENERR;
442 }
443 for (portstr = s; !ISSPACE(*portstr); portstr++)
444 ;
445 if (!*portstr) {
446 snmp_log(LOG_ERR, "unrecognized -T arg: %s\n", s);
447 free(s);
448 return SNMP_ERR_GENERR;
449 }
450 for (*portstr++ = 0; ISSPACE(*portstr); portstr++)
451 ;
452
453 n = pn = strtoul(portstr, &p, 0);
454 if (n != pn || (*p && !ISSPACE(*p))) {
455 snmp_log(LOG_ERR, "unrecognized -T arg: %s\n", s);
456 free(s);
457 return SNMP_ERR_GENERR;
458 }
459
460 hp = gethostbyname(s);
461 if (!hp) {
462 snmp_log(LOG_ERR, "unknown host name %s\n", s);
463 free(s);
464 return SNMP_ERR_GENERR;
465 }
466
467 vcli_sa.sin_family = hp->h_addrtype;
468 if (vcli_sa.sin_family != AF_INET) {
469 snmp_log(LOG_ERR, "unknown host name %s\n", s);
470 free(s);
471 return SNMP_ERR_GENERR;
472 }
473
474 memmove(&vcli_sa.sin_addr, hp->h_addr, 4);
475 vcli_sa.sin_port = htons(pn);
476
477 conn->fd = open_socket(&vcli_sa, s);
478 free(s);
479 if (conn->fd == -1)
480 return SNMP_ERR_GENERR;
481
482 if (!VSM_Get(vd, &vt, "Arg", "-S", "")) {
483 snmp_log(LOG_ERR, "no -S arg in shared memory\n");
484 return SNMP_ERR_GENERR;
485 }
486 DEBUGMSGTL(("vcli_mib", "-S '%s'\n", vt.b));
487 s = strdup(vt.b);
488 if (!s) {
489 snmp_log(LOG_ERR, "out of memory\n");
490 return SNMP_ERR_GENERR;
491 }
492 conn->secret = s;
493
494 if (vcli_handshake(conn)) {
495 vcli_disconnect(conn);
496 return SNMP_ERR_GENERR;
497 }
498 return SNMP_ERR_NOERROR;
499}

Return to:

Send suggestions and report system problems to the System administrator.