From patchwork Fri Nov 10 05:39:46 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Fran=C3=A7ois_Kooman?= X-Patchwork-Id: 58 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director4.mail.ord1d.rsapps.net ([172.27.255.54]) by backend31.mail.ord1d.rsapps.net (Dovecot) with LMTP id hXIVAsXaBVqjPgAAgoeIoA for ; Fri, 10 Nov 2017 11:58:45 -0500 Received: from proxy5.mail.iad3a.rsapps.net ([172.27.255.54]) by director4.mail.ord1d.rsapps.net (Dovecot) with LMTP id Jd3wFsXaBVqcIQAAHDmxtw ; Fri, 10 Nov 2017 11:58:45 -0500 Received: from smtp7.gate.iad3a ([172.27.255.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy5.mail.iad3a.rsapps.net (Dovecot) with LMTP id yi3lFcXaBVpbfgAAhn5joQ ; Fri, 10 Nov 2017 11:58:45 -0500 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.34.181.88] Authentication-Results: smtp7.gate.iad3a.rsapps.net; iprev=pass policy.iprev="216.34.181.88"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dkim=fail (signature verification failed) header.d=tuxed.net; dmarc=fail (p=none; dis=none) header.from=tuxed.net X-Classification-ID: 6942ffc6-c638-11e7-81f6-525400bbebb8-1-1 Received: from [216.34.181.88] ([216.34.181.88:4852] helo=lists.sourceforge.net) by smtp7.gate.iad3a.rsapps.net (envelope-from ) (ecelerity 4.2.1.56364 r(Core:4.2.1.14)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 1B/0D-14693-4CAD50A5; Fri, 10 Nov 2017 11:58:44 -0500 Received: from localhost ([127.0.0.1] helo=sfs-ml-1.v29.ch3.sourceforge.com) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.89) (envelope-from ) id 1eDCdC-0004an-1z; Fri, 10 Nov 2017 16:58:14 +0000 Received: from sfi-mx-3.v28.ch3.sourceforge.com ([172.29.28.193] helo=mx.sourceforge.net) by sfs-ml-1.v29.ch3.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89) (envelope-from ) id 1eDCdA-0004a1-Ey for openvpn-devel@lists.sourceforge.net; Fri, 10 Nov 2017 16:58:12 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To: MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=lSAeUD5+P4UEz4zXI1qXM/fxocBBAr8/p8rrBilZ3mc=; b=OJti2+9fY8O/iy+hbTEk9vZvr3 c+2NjOpcY3lWixKeAcRFp79U5JrNpXjtVVsVVxJfQHUBecBFT7xb1grW/NDHUbtwquDqyzpOUsdBn zSl/bxL1/Ij2XMWoBZYEr1UeWzCFVy+FC7ddSQ29OzVAv9gmUnQssMpgirFOxJeMyIHs=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:MIME-Version: Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=lSAeUD5+P4UEz4zXI1qXM/fxocBBAr8/p8rrBilZ3mc=; b=GUQiYXqQbXkmCbdOBVHEUNaeN2 2hMIqYayJEQ/jiIP+mcYn3Bv0RXnSQmumTkOGRmOUK9mdT1UqygsgbHA7yT198INoyJuPYv9kb4xL IJQVvsuLk7UgW5WtA7hGXazm2ZmhSW7MVEmr152Dbi73yeTW6koM308s+MHhzHqgOzDc=; Received: from helium.tuxed.net ([178.162.221.181]) by sfi-mx-3.v28.ch3.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89) id 1eDCd8-0003x0-KB for openvpn-devel@lists.sourceforge.net; Fri, 10 Nov 2017 16:58:12 +0000 Received: from fralen-tuxed-net.intranet.astaro.de (unknown [IPv6:2001:610:450:10::1000]) by helium.tuxed.net (Postfix) with ESMTPSA id AA2BB1000C6; Fri, 10 Nov 2017 16:39:32 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 helium.tuxed.net AA2BB1000C6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tuxed.net; s=default; t=1510331972; bh=lSAeUD5+P4UEz4zXI1qXM/fxocBBAr8/p8rrBilZ3mc=; h=From:To:Cc:Subject:Date:From; b=JJo9HWm0v95uyfWHgF1scbny2t4x4WoUBSaouPMFMdIYHXOQLlrZhX93dur+cJ2ff gLxHVPYxGUBV1GcXtodjDtG+Y2vP3t7aOI4/J7EWB40GiuDJqJGQlqAk7wdrv8qTy8 In5borT2GsGHcbeLItZ+0DhFLUuMTgoSkLBzvnrUythnaNHg0qGyZKdoDNa363H2Gy NVjDF7gkfV6eNhyEg1ADEa5spZOWy47hTpjwrd828oxNWAJMnt+PHeTjZSkVHxW1G6 +HQe5/DFgzOjTELqC1NizT6TTscvrR65xoHq+WTMCaTJc+0yAPTgVrh63LtP/OphkT rQm7V+71SwBlg== From: =?utf-8?q?Fran=C3=A7ois_Kooman?= To: openvpn-devel@lists.sourceforge.net Date: Fri, 10 Nov 2017 17:39:46 +0100 Message-Id: <20171110163946.7656-1-fkooman@tuxed.net> X-Mailer: git-send-email 2.13.6 X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 SPF_PASS SPF: sender matches SPF record -0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-Headers-End: 1eDCd8-0003x0-KB Subject: [Openvpn-devel] [PATCH] Implement "status 4" (JSON) for management interface X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox Parsing CSV can be cumbersome in depending software, so instead offer JSON as well using "status 4". The "status 4" command uses the same keys/values as "status 2" and "status 3", just formatted as JSON. --- src/openvpn/multi.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 82a0b9d9..3e82431b 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1014,6 +1014,102 @@ multi_print_status(struct multi_context *m, struct status_output *so, const int status_printf(so, "END"); } + else if (version == 4) + { + /* + * Status file version 4 (JSON) + */ + status_printf(so, "{"); + status_printf(so, "\"TITLE\": \"%s\",", title_string); + status_printf(so, "\"TIME\": \"%s\",", time_string(now, 0, false, &gc_top)); + /* UNIX_TIME added here instead of making it part of TIME as well + as in status 2/3 */ + status_printf(so, "\"UNIX_TIME\": %u,", (unsigned int)now); + status_printf(so, "\"CLIENT_LIST\": ["); + + /* JSON needs a "," between items, but not at the last position, + because I was unable to figure out how to determine if we + iterate over the last item, we inverse it by prepending + additional items with a comma */ + int is_first = 1; + hash_iterator_init(m->hash, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct gc_arena gc = gc_new(); + const struct multi_instance *mi = (struct multi_instance *) he->value; + + if (!mi->halt) + { + if(0 == is_first) { + status_printf(so, ","); + } else { + is_first = 0; + } + status_printf(so, "{"); + status_printf(so, "\"Common Name\": \"%s\",", tls_common_name(mi->context.c2.tls_multi, false)); + status_printf(so, "\"Real Address\": \"%s\",", mroute_addr_print(&mi->real, &gc)); + status_printf(so, "\"Virtual Address\": \"%s\",", print_in_addr_t(mi->reporting_addr, IA_EMPTY_IF_UNDEF, &gc)); + status_printf(so, "\"Virtual IPv6 Address\": \"%s\",", print_in6_addr(mi->reporting_addr_ipv6, IA_EMPTY_IF_UNDEF, &gc)); + status_printf(so, "\"Bytes Received\": " counter_format ",", mi->context.c2.link_read_bytes); + status_printf(so, "\"Bytes Sent\": " counter_format ",", mi->context.c2.link_write_bytes); + status_printf(so, "\"Connected Since\": \"%s\",", time_string(mi->created, 0, false, &gc)); + status_printf(so, "\"Connected Since (time_t)\": %u,", (unsigned int)mi->created); + status_printf(so, "\"Username\": \"%s\",", tls_username(mi->context.c2.tls_multi, false)); +#ifdef MANAGEMENT_DEF_AUTH + status_printf(so, "\"Client ID\": %lu,", mi->context.c2.mda_context.cid); +#endif + status_printf(so, "\"Peer ID\": %" PRIu32, mi->context.c2.tls_multi ? mi->context.c2.tls_multi->peer_id : UINT32_MAX); + status_printf(so, "}"); + } + gc_free(&gc); + } + hash_iterator_free(&hi); + + status_printf(so, "],"); + status_printf(so, "\"ROUTING_TABLE\": ["); + + is_first = 1; + hash_iterator_init(m->vhash, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct gc_arena gc = gc_new(); + const struct multi_route *route = (struct multi_route *) he->value; + + if (multi_route_defined(m, route)) + { + const struct multi_instance *mi = route->instance; + const struct mroute_addr *ma = &route->addr; + char flags[2] = {0, 0}; + + if (route->flags & MULTI_ROUTE_CACHE) + { + flags[0] = 'C'; + } + if(0 == is_first) { + status_printf(so, ","); + } else { + is_first = 0; + } + status_printf(so, "{\"Virtual Address\": \"%s%s\",", mroute_addr_print(ma, &gc), flags); + status_printf(so, "\"Common Name\": \"%s\",", tls_common_name(mi->context.c2.tls_multi, false)); + status_printf(so, "\"Real Address\": \"%s\",", mroute_addr_print(&mi->real, &gc)); + status_printf(so, "\"Last Ref\": \"%s\",", time_string(route->last_reference, 0, false, &gc)); + status_printf(so, "\"Last Ref (time_t)\": %u}", (unsigned int)route->last_reference); + } + gc_free(&gc); + } + hash_iterator_free(&hi); + status_printf(so, "]"); + + if (m->mbuf) + { + status_printf(so, ",\"GLOBAL_STATS\": {"); + status_printf(so, "\"Max bcast/mcast queue length\": %d", mbuf_maximum_queued(m->mbuf)); + status_printf(so, "}"); + } + status_printf(so, "}"); + status_printf(so, "END"); + } else { status_printf(so, "ERROR: bad status format version number");