From 46eff942e4e3b3c7ddbecd170dd7d5078b8debc0 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Sat, 19 Aug 2017 17:04:04 -0400 Subject: [feature] add twisted protocol for handling openvpn management --- tests/unit/vpn/session1.data | 34 ++++++++++ tests/unit/vpn/session2.data | 38 +++++++++++ tests/unit/vpn/test_management.py | 129 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 tests/unit/vpn/session1.data create mode 100644 tests/unit/vpn/session2.data create mode 100644 tests/unit/vpn/test_management.py (limited to 'tests/unit/vpn') diff --git a/tests/unit/vpn/session1.data b/tests/unit/vpn/session1.data new file mode 100644 index 00000000..5381bad3 --- /dev/null +++ b/tests/unit/vpn/session1.data @@ -0,0 +1,34 @@ +>INFO:OpenVPN Management Interface Version 1 -- type 'help' for more info +SUCCESS: real-time log notification set to ON +OpenVPN Version: OpenVPN 2.4.0 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Jun 22 2017 +Management Version: 1 +END +SUCCESS: pid=23783 +SUCCESS: real-time state notification set to ON +SUCCESS: bytecount interval changed +>BYTECOUNT:26,14 +>STATE:1503010298,AUTH,,,,,, +>LOG:1503010302,I,[otter.demo.bitmask.net] Peer Connection Initiated with [AF_INET]46.165.242.169:443 +>STATE:1503010303,GET_CONFIG,,,,,, +>BYTECOUNT:5573,3716 +>LOG:1503010303,W,Note: option tun-ipv6 is ignored because modern operating systems do not need special IPv6 tun handling anymore. +>LOG:1503010303,I,TUN/TAP device tun0 opened +>LOG:1503010303,D,do_ifconfig, tt->did_ifconfig_ipv6_setup=1 +>STATE:1503010303,ASSIGN_IP,,10.42.0.18,,,,,2001:db8:123::1010 +>LOG:1503010303,I,/sbin/ip link set dev tun0 up mtu 1500 +>LOG:1503010303,I,/sbin/ip addr add dev tun0 10.42.0.18/21 broadcast 10.42.7.255 +>LOG:1503010303,I,/sbin/ip -6 addr add 2001:db8:123::1010/64 dev tun0 +>LOG:1503010303,W,ERROR: Linux route add command failed: external program exited with error status: 2 +>LOG:1503010304,I,add_route_ipv6(2000::/3 -> 2001:db8:123::1 metric -1) dev tun0 +>LOG:1503010304,I,GID set to nogroup +>LOG:1503010304,I,UID set to nobody +>LOG:1503010304,I,Initialization Sequence Completed +>STATE:1503010304,CONNECTED,SUCCESS,10.42.0.18,46.165.242.169,443,,,2001:db8:123::1010 +>BYTECOUNT:6279,4102 +>BYTECOUNT:6577,4400 +>BYTECOUNT:6923,4847 +>BYTECOUNT:7237,4996 +>BYTECOUNT:7732,5443 +>BYTECOUNT:10355,6055 +>BYTECOUNT:17168,7657 + diff --git a/tests/unit/vpn/session2.data b/tests/unit/vpn/session2.data new file mode 100644 index 00000000..cd2ece51 --- /dev/null +++ b/tests/unit/vpn/session2.data @@ -0,0 +1,38 @@ +>INFO:OpenVPN Management Interface Version 1 -- type 'help' for more info +SUCCESS: real-time log notification set to ON +OpenVPN Version: OpenVPN 2.4.0 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Jun 22 2017 +Management Version: 1 +END +SUCCESS: pid=30641 +SUCCESS: real-time state notification set to ON +SUCCESS: bytecount interval changed +>BYTECOUNT:26,14 +>STATE:1503079741,AUTH,,,,,, +>BYTECOUNT:5168,3078 +>LOG:1503079746,I,[otter.demo.bitmask.net] Peer Connection Initiated with [AF_INET]46.165.242.169:443 +>STATE:1503079747,GET_CONFIG,,,,,, +>LOG:1503079748,W,Note: option tun-ipv6 is ignored because modern operating systems do not need special IPv6 tun handling anymore. +>LOG:1503079748,I,TUN/TAP device tun0 opened +>LOG:1503079748,D,do_ifconfig, tt->did_ifconfig_ipv6_setup=1 +>STATE:1503079748,ASSIGN_IP,,10.42.0.12,,,,,2001:db8:123::100a +>LOG:1503079748,I,/sbin/ip link set dev tun0 up mtu 1500 +>LOG:1503079748,I,/sbin/ip addr add dev tun0 10.42.0.12/21 broadcast 10.42.7.255 +>LOG:1503079748,I,/sbin/ip -6 addr add 2001:db8:123::100a/64 dev tun0 +>LOG:1503079748,W,ERROR: Linux route add command failed: external program exited with error status: 2 +>LOG:1503079748,I,add_route_ipv6(2000::/3 -> 2001:db8:123::1 metric -1) dev tun0 +>LOG:1503079748,I,GID set to nogroup +>LOG:1503079748,I,UID set to nobody +>LOG:1503079748,I,Initialization Sequence Completed +>STATE:1503079748,CONNECTED,SUCCESS,10.42.0.12,46.165.242.169,443,,,2001:db8:123::100a +SUCCESS: signal SIGTERM thrown +>LOG:1503079751,W,ERROR: Linux route delete command failed: external program exited with error status: 2 +>LOG:1503079751,W,ERROR: Linux route delete command failed: external program exited with error status: 2 +>LOG:1503079751,W,ERROR: Linux route delete command failed: external program exited with error status: 2 +>LOG:1503079751,I,delete_route_ipv6(2000::/3) +>LOG:1503079751,W,ERROR: Linux route -6/-A inet6 del command failed: external program exited with error status: 2 +>LOG:1503079751,I,/sbin/ip addr del dev tun0 10.42.0.12/21 +>LOG:1503079751,W,Linux ip addr del failed: external program exited with error status: 2 +>LOG:1503079751,I,/sbin/ip -6 addr del 2001:db8:123::100a/64 dev tun0 +>LOG:1503079751,W,Linux ip -6 addr del failed: external program exited with error status: 2 +>LOG:1503079751,I,SIGTERM[hard,] received, process exiting +>STATE:1503079751,EXITING,SIGTERM,,,,, diff --git a/tests/unit/vpn/test_management.py b/tests/unit/vpn/test_management.py new file mode 100644 index 00000000..c70d768b --- /dev/null +++ b/tests/unit/vpn/test_management.py @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- +# test_management.py +# Copyright (C) 2017 LEAP Encryption Access Project +# +# This program 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 of the License, or +# (at your option) any later version. +# +# This program 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 this program. If not, see . + +""" +Tests for the VPN Management Interface +""" + +import StringIO + +from twisted.trial import unittest +from leap.bitmask.vpn.management import ManagementProtocol + + +session1 = open('session1.data').readlines() +session2 = open('session2.data').readlines() + + +def feed_the_protocol(protocol, data): + for line in data: + protocol.lineReceived(line) + + +class StateListener(object): + + def __init__(self): + self.states = [] + + def change_state(self, state): + self.states.append(state) + + +class ManagementTestCase(unittest.TestCase): + + def test_final_state_is_connected(self): + proto = ManagementProtocol() + feed_the_protocol(proto, session1) + assert proto.state.state == 'CONNECTED' + assert proto.state.simple == 'ON' + assert proto.remote == '46.165.242.169' + + def test_final_state_stopping(self): + proto = ManagementProtocol() + feed_the_protocol(proto, session2) + assert proto.state.state == 'EXITING' + assert proto.state.simple == 'STOPPING' + + def test_get_state_history(self): + proto = ManagementProtocol() + feed_the_protocol(proto, session1) + log = proto.getStateHistory() + states = [st.state for st in log.values()] + assert len(log) == 4 + assert states == ['AUTH', 'GET_CONFIG', 'ASSIGN_IP', 'CONNECTED'] + + def test_state_listener(self): + proto = ManagementProtocol() + listener = StateListener() + proto.addStateListener(listener) + feed_the_protocol(proto, session1) + states = [st.state for st in listener.states] + assert states == ['AUTH', 'GET_CONFIG', 'ASSIGN_IP', 'CONNECTED'] + + def test_bytecount(self): + proto = ManagementProtocol() + feed_the_protocol(proto, session1) + assert proto.traffic.down == 17168 + assert proto.traffic.up == 7657 + + def test_bytecount_rate(self): + proto = ManagementProtocol() + proto.traffic.update(1024, 512, 1) + proto.traffic.update(2048, 1024, 2) + print proto.traffic._buf + assert proto.traffic.down == 2048 + assert proto.traffic.up == 1024 + assert proto.traffic.get_rate() == ['1.0 K', '512.0 B'] + + def test_get_pid(self): + proto = ManagementProtocol() + proto.transport = StringIO.StringIO() + assert proto.pid == None + proto.get_pid() + pid_lines = ['SUCCESS: pid=99999'] + feed_the_protocol(proto, pid_lines) + assert proto.pid == 99999 + + def test_parse_version_string(self): + proto = ManagementProtocol() + proto.transport = StringIO.StringIO() + assert proto.openvpn_version == '' + feed_the_protocol(proto, session1[2:4]) + proto.getVersion() + feed_the_protocol(proto, ['END']) + assert proto.openvpn_version.startswith('OpenVPN 2.4.0') + + def test_get_info(self): + proto = ManagementProtocol() + proto.transport = StringIO.StringIO() + feed_the_protocol(proto, session1) + + feed_the_protocol(proto, session1[2:4]) + proto.getVersion() + feed_the_protocol(proto, ['END']) + proto.get_pid() + pid_lines = ['SUCCESS: pid=23783'] + feed_the_protocol(proto, pid_lines) + + info = proto.getInfo() + assert info['remote'] == '46.165.242.169' + assert info['rport'] == '443' + assert info['state'] == 'CONNECTED' + assert info['state_simple'] == 'ON' + assert info['state_legend'] == 'Initialization Sequence Completed' + assert info['openvpn_version'].startswith('OpenVPN 2.4.0') + assert info['pid'] == 23783 -- cgit v1.2.3