Jamie- / openvpn-api

A Python API for the OpenVPN management interface.
MIT License
60 stars 18 forks source link

Calling get_state() results in an Infinite loop #22

Closed jakobahlin closed 4 years ago

jakobahlin commented 4 years ago

Twice now I've run into an issue that I cannot reproduce. When calling get_state() the process is getting stuck in an infinite loop. Running strace on the process I see a loop of this:

poll([{fd=3, events=POLLIN}], 1, 3000)  = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "", 4096, 0, NULL, NULL)    = 0
poll([{fd=3, events=POLLIN}], 1, 3000)  = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "", 4096, 0, NULL, NULL)    = 0
poll([{fd=3, events=POLLIN}], 1, 3000)  = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "", 4096, 0, NULL, NULL)    = 0
poll([{fd=3, events=POLLIN}], 1, 3000)  = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "", 4096, 0, NULL, NULL)    = 0
poll([{fd=3, events=POLLIN}], 1, 3000)  = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "", 4096, 0, NULL, NULL)    = 0
poll([{fd=3, events=POLLIN}], 1, 3000)  = 1 ([{fd=3, revents=POLLIN}])
recvfrom(3, "", 4096, 0, NULL, NULL)    = 0

Running code from master 2020-06-14

UPDATE: Looking at the openvpn log file, I may have had parallel (attempted) connections to the management interface at the same time (two scheduled scripts at the same time invoking the mgmt interface), which is not supported as I understand it.

I'm not sure what state the tunnel was in at the moment when the call causing the infinite loop started, but when I found the problem it was in state TCP_CONNECT. The tunnel had not been able to connect for days, so it could not have been in state CONNECTED anyway.

Tcp connection to openvpn management port is in state CLOSE_WAIT: tcp 0 0 127.0.0.1:39518 127.0.0.1:8897 CLOSE_WAIT

My code:

def main():
    managementPort = sys.argv[1]
    v = openvpn_api.VPN('localhost', managementPort)
    try:
        v.connect()
        state = v.get_state().state_name
        print(f"{state}")

    except openvpn_api.util.errors.ConnectError as e:
        print("TIMEOUT")
        print(f"Exception: {e}",file=sys.stderr)
    except Exception as e:
        print("ERROR")
        t = type(e)
        print(f"Exception: {e}, Type: {t}",file=sys.stderr)
        traceback.print_exc()
    finally:
        v.disconnect()

if __name__ == "__main__":
    main()
jakobahlin commented 4 years ago

Looking at the openvpn log file, I may have had parallel (attempted) connections to the management interface at the same time (two scheduled scripts at the same time invoking the mgmt interface), which is not supported as I understand it.

Jamie- commented 4 years ago

That is correct, you can only connect a single client to the management interface by design of OpenVPN. If you are able to reproduce with only one process using the interface feel free to re-open :)

jakobahlin commented 4 years ago

Thanks for your reply and fair enough :) Should it end up in an infinite loop using 100 cpu though?

Jamie- commented 4 years ago

Probably not - though there's a branch which completely changes the socket logic I've been working on which should fix it. Interestingly I think I might have reproduced the kind of thing you experienced though in a different way on changed code.

In any case, should be fixed in the next version