Browse code

Extended Management Interface "bytecount" command to work when OpenVPN is running as a server.

Documented Management Interface "bytecount" command in
management/management-notes.txt.


git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@3452 e7ae566f-a301-0410-adde-c780ea21d3b5

james authored on 2008/10/24 18:21:40
Showing 5 changed files
... ...
@@ -707,12 +707,17 @@ process_incoming_link (struct context *c)
707 707
       c->c2.original_recv_size = c->c2.buf.len;
708 708
 #ifdef ENABLE_MANAGEMENT
709 709
       if (management)
710
-	management_bytes_in (management, c->c2.buf.len);
710
+	{
711
+	  management_bytes_in (management, c->c2.buf.len);
712
+#ifdef MANAGEMENT_DEF_AUTH
713
+	  management_bytes_server (management, &c->c2.link_read_bytes, &c->c2.link_write_bytes, &c->c2.mda_context);
714
+#endif
715
+	}
711 716
 #endif
712 717
     }
713 718
   else
714 719
     c->c2.original_recv_size = 0;
715
-
720
+  
716 721
 #ifdef ENABLE_DEBUG
717 722
   /* take action to corrupt packet if we are in gremlin test mode */
718 723
   if (c->options.gremlin) {
... ...
@@ -1100,7 +1105,12 @@ process_outgoing_link (struct context *c)
1100 1100
 	      c->c2.link_write_bytes += size;
1101 1101
 #ifdef ENABLE_MANAGEMENT
1102 1102
 	      if (management)
1103
-		management_bytes_out (management, size);
1103
+		{
1104
+		  management_bytes_out (management, size);
1105
+#ifdef MANAGEMENT_DEF_AUTH
1106
+		  management_bytes_server (management, &c->c2.link_read_bytes, &c->c2.link_write_bytes, &c->c2.mda_context);
1107
+#endif
1108
+		}
1104 1109
 #endif
1105 1110
 	    }
1106 1111
 	}
... ...
@@ -367,11 +367,15 @@ man_status (struct management *man, const int version, struct status_output *so)
367 367
 static void
368 368
 man_bytecount (struct management *man, const int update_seconds)
369 369
 {
370
-  man->connection.bytecount_update_seconds = update_seconds;
370
+  if (update_seconds >= 0)
371
+    man->connection.bytecount_update_seconds = update_seconds;
372
+  else
373
+    man->connection.bytecount_update_seconds = 0;
374
+  msg (M_CLIENT, "SUCCESS: bytecount interval changed");
371 375
 }
372 376
 
373 377
 void
374
-man_bytecount_output (struct management *man)
378
+man_bytecount_output_client (struct management *man)
375 379
 {
376 380
   char in[32];
377 381
   char out[32];
... ...
@@ -382,6 +386,25 @@ man_bytecount_output (struct management *man)
382 382
   man->connection.bytecount_last_update = now;
383 383
 }
384 384
 
385
+#ifdef MANAGEMENT_DEF_AUTH
386
+
387
+void
388
+man_bytecount_output_server (struct management *man,
389
+			     const counter_type *bytes_in_total,
390
+			     const counter_type *bytes_out_total,
391
+			     struct man_def_auth_context *mdac)
392
+{
393
+  char in[32];
394
+  char out[32];
395
+  /* do in a roundabout way to work around possible mingw or mingw-glibc bug */
396
+  openvpn_snprintf (in, sizeof (in), counter_format, *bytes_in_total);
397
+  openvpn_snprintf (out, sizeof (out), counter_format, *bytes_out_total);
398
+  msg (M_CLIENT, ">BYTECOUNT_CLI:%lu,%s,%s", mdac->cid, in, out);
399
+  mdac->bytecount_last_update = now;
400
+}
401
+
402
+#endif
403
+
385 404
 static void
386 405
 man_kill (struct management *man, const char *victim)
387 406
 {
... ...
@@ -51,6 +51,8 @@ struct man_def_auth_context {
51 51
   unsigned int flags;
52 52
 
53 53
   unsigned int mda_key_id_counter;
54
+
55
+  time_t bytecount_last_update;
54 56
 };
55 57
 #endif
56 58
 
... ...
@@ -143,6 +145,10 @@ log_history_capacity (const struct log_history *h)
143 143
 struct management_callback
144 144
 {
145 145
   void *arg;
146
+
147
+# define MCF_SERVER (1<<0) /* is OpenVPN being run as a server? */
148
+  unsigned int flags;
149
+
146 150
   void (*status) (void *arg, const int version, struct status_output *so);
147 151
   void (*show_net) (void *arg, const int msglevel);
148 152
   int (*kill_by_cn) (void *arg, const char *common_name);
... ...
@@ -432,31 +438,65 @@ void management_auth_failure (struct management *man, const char *type);
432 432
  * These functions drive the bytecount in/out counters.
433 433
  */
434 434
 
435
-void man_bytecount_output (struct management *man);
435
+void man_bytecount_output_client (struct management *man);
436 436
 
437 437
 static inline void
438
-man_bytecount_possible_output (struct management *man)
438
+man_bytecount_possible_output_client (struct management *man)
439 439
 {
440 440
   if (man->connection.bytecount_update_seconds > 0
441 441
       && now >= man->connection.bytecount_last_update
442 442
       + man->connection.bytecount_update_seconds)
443
-    man_bytecount_output (man);
443
+    man_bytecount_output_client (man);
444 444
 }
445 445
 
446 446
 static inline void
447
-management_bytes_out (struct management *man, const int size)
447
+management_bytes_out_client (struct management *man, const int size)
448 448
 {
449 449
   man->persist.bytes_out += size;
450
-  man_bytecount_possible_output (man);
450
+  man_bytecount_possible_output_client (man);
451 451
 }
452 452
 
453 453
 static inline void
454
-management_bytes_in (struct management *man, const int size)
454
+management_bytes_in_client (struct management *man, const int size)
455 455
 {
456 456
   man->persist.bytes_in += size;
457
-  man_bytecount_possible_output (man);
457
+  man_bytecount_possible_output_client (man);
458 458
 }
459 459
 
460
-#endif
460
+static inline void
461
+management_bytes_out (struct management *man, const int size)
462
+{
463
+  if (!(man->persist.callback.flags & MCF_SERVER))
464
+    management_bytes_out_client (man, size);
465
+}
461 466
 
467
+static inline void
468
+management_bytes_in (struct management *man, const int size)
469
+{
470
+  if (!(man->persist.callback.flags & MCF_SERVER))
471
+    management_bytes_in_client (man, size);
472
+}
473
+
474
+#ifdef MANAGEMENT_DEF_AUTH
475
+
476
+static inline void
477
+management_bytes_server (struct management *man,
478
+			 const counter_type *bytes_in_total,
479
+			 const counter_type *bytes_out_total,
480
+			 struct man_def_auth_context *mdac)
481
+{
482
+  void man_bytecount_output_server (struct management *man,
483
+				    const counter_type *bytes_in_total,
484
+				    const counter_type *bytes_out_total,
485
+				    struct man_def_auth_context *mdac);
486
+
487
+  if (man->connection.bytecount_update_seconds > 0
488
+      && now >= mdac->bytecount_last_update + man->connection.bytecount_update_seconds
489
+      && (mdac->flags & (DAF_CONNECTION_ESTABLISHED|DAF_CONNECTION_CLOSED)) == DAF_CONNECTION_ESTABLISHED)
490
+    man_bytecount_output_server (man, bytes_in_total, bytes_out_total, mdac);
491
+}
492
+
493
+#endif /* MANAGEMENT_DEF_AUTH */
494
+
495
+#endif
462 496
 #endif
... ...
@@ -3,26 +3,24 @@ OpenVPN Management Interface Notes
3 3
 
4 4
 The OpenVPN Management interface allows OpenVPN to
5 5
 be administratively controlled from an external program via
6
-a TCP socket.
6
+a TCP or unix domain socket.
7 7
 
8
-The interface has been specifically designed for GUI developers
9
-and those who would like to programmatically or remotely control
10
-an OpenVPN daemon.
8
+The interface has been specifically designed for developers
9
+who would like to programmatically or remotely control
10
+an OpenVPN daemon, and can be used when OpenVPN is running
11
+as a client or server.
11 12
 
12 13
 The management interface is implemented using a client/server TCP
13
-connection, where OpenVPN will listen on a provided IP address
14
-and port for incoming management client connections.
14
+connection or unix domain socket where OpenVPN will listen on a
15
+provided IP address and port for incoming management client connections.
15 16
 
16 17
 The management protocol is currently cleartext without an explicit
17 18
 security layer.  For this reason, it is recommended that the
18
-management interface either listen on localhost (127.0.0.1)
19
-or on the local VPN address.  It's possible to remotely connect
20
-to the management interface over the VPN itself, though some
21
-capabilities will be limited in this mode, such as the ability
22
-to provide private key passwords.
23
-
24
-Future versions of the management interface may allow out-of-band
25
-connections (i.e. not over the VPN) and secured with SSL/TLS.
19
+management interface either listen on a unix domain socket,
20
+localhost (127.0.0.1), or on the local VPN address.  It's possible
21
+to remotely connect to the management interface over the VPN itself,
22
+though some capabilities will be limited in this mode, such as the
23
+ability to provide private key passwords.
26 24
 
27 25
 The management interface is enabled in the OpenVPN
28 26
 configuration file using the following directive:
... ...
@@ -39,6 +37,44 @@ a telnet client which understands "raw" mode).
39 39
 Once connected to the management port, you can use
40 40
 the "help" command to list all commands.
41 41
 
42
+COMMAND -- bytecount
43
+--------------------
44
+
45
+The bytecount command is used to request real-time notification
46
+of OpenVPN bandwidth usage.
47
+
48
+Command syntax:
49
+
50
+  bytecount n (where n > 0) -- set up automatic notification of
51
+                               bandwidth usage once every n seconds
52
+  bytecount 0 -- turn off bytecount notifications
53
+
54
+If OpenVPN is running as a client, the bytecount notification
55
+will look like this:
56
+
57
+  >BYTECOUNT:{BYTES_IN},{BYTES_OUT}
58
+
59
+BYTES_IN is the number of bytes that have been received from
60
+the server and BYTES_OUT is the number of bytes that have been
61
+sent to the server.
62
+
63
+If OpenVPN is running as a server, the bytecount notification
64
+will look like this:
65
+
66
+  >BYTECOUNT_CLI:{CID},{BYTES_IN},{BYTES_OUT}
67
+ 
68
+CID is the Client ID, BYTES_IN is the number of bytes that have
69
+been received from the client and BYTES_OUT is the number of
70
+bytes that have been sent to the client.
71
+
72
+Note that when the bytecount command is used on the server, every
73
+connected client will report its bandwidth numbers once every n
74
+seconds.
75
+
76
+When the client disconnects, the final bandwidth numbers will be
77
+placed in the 'bytes_received' and 'bytes_sent' environmental variables
78
+as included in the >CLIENT:DISCONNECT notification.
79
+
42 80
 COMMAND -- echo
43 81
 ---------------
44 82
 
... ...
@@ -661,6 +697,14 @@ column and are immediately followed by a type keyword
661 661
 indicating the type of real-time message.  The following
662 662
 types are currently defined:
663 663
 
664
+BYTECOUNT -- Real-time bandwidth usage notification, as enabled
665
+             by "bytecount" command when OpenVPN is running as
666
+             a client.
667
+
668
+BYTECOUNT_CLI -- Real-time bandwidth usage notification per-client,
669
+	         as enabled by "bytecount" command when OpenVPN is
670
+                 running as a server.
671
+
664 672
 CLIENT   -- Notification of client connections and disconnections
665 673
             on an OpenVPN server.  Enabled when OpenVPN is started
666 674
             with the --management-client-auth option.  CLIENT
... ...
@@ -437,6 +437,13 @@ multi_del_iroutes (struct multi_context *m,
437 437
 }
438 438
 
439 439
 static void
440
+setenv_stats (struct context *c)
441
+{
442
+  setenv_counter (c->c2.es, "bytes_received", c->c2.link_read_bytes);
443
+  setenv_counter (c->c2.es, "bytes_sent", c->c2.link_write_bytes);
444
+}
445
+
446
+static void
440 447
 multi_client_disconnect_setenv (struct multi_context *m,
441 448
 				struct multi_instance *mi)
442 449
 {
... ...
@@ -444,8 +451,7 @@ multi_client_disconnect_setenv (struct multi_context *m,
444 444
   setenv_trusted (mi->context.c2.es, get_link_socket_info (&mi->context));
445 445
 
446 446
   /* setenv stats */
447
-  setenv_counter (mi->context.c2.es, "bytes_received", mi->context.c2.link_read_bytes);
448
-  setenv_counter (mi->context.c2.es, "bytes_sent", mi->context.c2.link_write_bytes);
447
+  setenv_stats (&mi->context);
449 448
 
450 449
   /* setenv connection duration */
451 450
   {
... ...
@@ -2583,6 +2589,7 @@ init_management_callback_multi (struct multi_context *m)
2583 2583
       struct management_callback cb;
2584 2584
       CLEAR (cb);
2585 2585
       cb.arg = m;
2586
+      cb.flags = MCF_SERVER;
2586 2587
       cb.status = management_callback_status;
2587 2588
       cb.show_net = management_show_net_callback;
2588 2589
       cb.kill_by_cn = management_callback_kill_by_cn;