2
0
mirror of https://github.com/xcat2/confluent.git synced 2025-01-15 04:07:51 +00:00
confluent/bin/confetty
Jarrod Johnson 70fad4335a Advance state of the socket interface
Properly implement authentication and switch the protocol over to the tlv
based protocol.  Abandon all thought of the socket being directly accessible.
Any CLI semantics will be in confetty and an appliance wishing to expose that CLI
directly should use standard ssh stuff with a shell of confetty.  The unix domain
authentication support makes this feasible (requires user creation push name into
confluent repository at the moment..)
2014-02-09 10:43:26 -05:00

180 lines
5.7 KiB
Python
Executable File

#!/usr/bin/env python
# ultimately, this should provide an interactive cli for navigating confluent
# tree and doing console with a socket. <ESC>]0;<string><BELL> can be used to
# present info such as whether it is in a console or other mode and, if in
# console, how many other connections are live and looking
# this means 'wcons' simply needs to make a terminal run and we'll take care of
# the title while providing more info
# this also means the socket interface needs to have ways to convey more
# interesting pieces of data (like concurrent connection count)
# socket will probably switch to a TLV scheme:
# 32 bit TL, 8 bits of type code and 24 bit size
# type codes:
# 0: string data
# 1: json data
# 24 bit size allows the peer to avoid having to do any particular parsing to
# understand message boundaries (which is a significant burden on the xCAT
# protocol)
# When in a console client mode, will recognize two escape sequences by
# default:
# Ctrl-E, c, ?: mimick conserver behavior
# ctrl-]: go to interactive prompt (telnet escape, but not telnet prompt)
# esc-( would interfere with normal esc use too much
# ~ I will not use for now...
import fcntl
import getpass
import optparse
import os
import select
import socket
import ssl
import sys
import termios
import tty
path = os.path.dirname(os.path.realpath(__file__))
path = os.path.realpath(os.path.join(path, '..'))
sys.path.append(path)
import confluent.common.tlvdata as tlvdata
SO_PASSCRED = 16
conserversequence = '\x05c' # ctrl-e, c
oldtcattr = termios.tcgetattr(sys.stdin.fileno())
server = None
def parseservervalue(serverstring):
if serverstring.find(']:') != -1:
server, port = serverstring[1:].split(']:')
elif serverstring[0] == '[':
server = serverstring[1:-1]
port = 4001
elif -1 != opts.server.find(':'):
server, port = opts.server.split(":")
else:
server = serverstring
port = 4001
return (server, port)
def exit(code=0):
termios.tcsetattr(sys.stdin.fileno(), termios.TCSANOW, oldtcattr)
server.shutdown(socket.SHUT_RDWR)
server.close()
sys.exit(code)
def conserver_command(fh, command):
while not command:
ready, _, _ = select.select((fh,), (), (), 1)
if ready:
command += fh.read()
if command[0] == '.':
print("disconnect]\r")
exit()
elif command[0] == '?':
print("help]\r")
print(". disconnect\r")
print("<cr> abort command\r")
elif command[0] == '\x0d':
print("ignored]\r")
else: #not a command at all..
print("unknown -- use '?']\r")
def check_escape_seq(input, fh):
while conserversequence.startswith(input):
if input.startswith(conserversequence): # We have full sequence
sys.stdout.write("[")
sys.stdout.flush()
return conserver_command(fh, input[len(conserversequence):])
ready, _, _ = select.select((fh,), (), (), 3)
if not ready: # 3 seconds of no typing
break
input += fh.read()
return input
def connect_unix_server(sockpath):
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, SO_PASSCRED, 1)
server.connect(sockpath)
return server
def connect_tls_server(serverstring):
host, port = parseservervalue(serverstring)
for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC,
socket.SOCK_STREAM):
af, socktype, proto, cononname, sa = res
try:
server = socket.socket(af, socktype, proto)
except:
server = None
continue
try:
server.settimeout(5)
server.connect(sa)
except:
server.close()
server = None
continue
break
if server is None:
sys.stderr.write("Failed to connect to %s\n" % serverstring)
sys.exit(1)
secserver = ssl.wrap_socket(server)
return secserver
parser = optparse.OptionParser()
parser.add_option("-s", "--server", dest="server",
help="TLS server to connect to", metavar="SERVER:PORT")
parser.add_option("-u", "--unixsocket", dest="unixsock",
help="TLS server to connect to", metavar="UNIXDOMAINSOCKET")
opts, args = parser.parse_args()
if opts.server: # going over a TLS network
server = connect_tls_server(opts.server)
elif opts.unixsock:
server = connect_unix_server(opts.unixsock)
#Next stop, reading and writing from whichever of stdin and server goes first.
#see pyghmi code for solconnect.py
banner = tlvdata.recv_tlvdata(server)
authinfo = tlvdata.recv_tlvdata(server)
while authinfo['authpassed'] != 1:
username = raw_input("Name: ")
passphrase = getpass.getpass("Passphrase: ")
tlvdata.send_tlvdata(server,
{'username': username, 'passphrase': passphrase})
authinfo = tlvdata.recv_tlvdata(server)
tty.setraw(sys.stdin.fileno())
fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
# clear on start can help with readable of TUI, but it
# can be annoying, so for now don't do it.
# sys.stdout.write('\x1b[H\x1b[J')
# sys.stdout.flush()
doexit = False
while not doexit:
rdylist, _, _ = select.select((sys.stdin, server), (), (), 60)
for fh in rdylist:
if fh == server:
#fh.read()
data = tlvdata.recv_tlvdata(fh)
if data:
sys.stdout.write(data)
sys.stdout.flush()
else:
doexit = True
sys.stdout.write("\r\n[remote disconnected]\r\n")
break
else:
input = fh.read()
input = check_escape_seq(input, fh)
if input:
tlvdata.send_tlvdata(server, input)
exit()