SSL raises version error only on re-connect attempt? - python

We have a server and client both running python3.
The client connects to the server and authenticates upon initialisation of the client. This completes without issue.
However, if the connection drops, the client catches the error (the socket.recv returning 0) and attempts to re-run the code that connects to the server).
The server recieves the initial request whilst listening on its given recieving socket and then once making a connection the next recv call raises the following error:
File "/usr/lib64/python3.7/ssl.py", line 1056, in recv
return self.read(buflen)
File "/usr/lib64/python3.7/ssl.py", line 931, in read
return self._sslobj.read(len)
ssl.SSLError: [SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:2570)
Why would this succeed upon the first connection but then raise this error thereafter? If the client is closed and restarted the error is avoided upon the next connection. However, if the server is closed and the client tries to connect once the server restarts this error is encountered.
At the client end the following error is raised:
File "\Our_Code", line 100, in make_connection
data = self.ssl_sock.recv(1024)
File "C:\Users\Home\AppData\Local\Programs\Python\Python39\lib\ssl.py", line 1226, in recv226, in recv
return self.read(buflen) 101, in read
File "C:\Users\Home\AppData\Local\Programs\Python\Python39\lib\ssl.py", line 1101, in read
return self._sslobj.read(len)
ssl.SSLError: [SSL] internal error (_ssl.c:2633)
This exact formultation suggests to me that the issue is actually with the client and some data that it is saving between reconnects. But it overwrites the sockets for a new connection so I thought all data from the previous connection would be discarded?
The connection function is as:
import socket
import ssl
def make_connection(self, email, password):
try:
self.ssl_sock = []
HOST = "9:9:99:999" # The server's hostname or IP address (not our actual IP)
PORT = 5432 # The port used by the server (not our actual port)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
self.ssl_sock = self.context.wrap_socket(sock)
password = password.encode('utf-8').strip()
password = base64.b64encode(password).decode("utf-8")
tcp_string = (f"^{email}*{password}$")
tcp_string = tcp_string.encode('utf-8')
self.ssl_sock.sendall(tcp_string)
data = self.ssl_sock.recv(1024)
data = data.decode('utf-8')
if data == "^good_connect$":
return True
else:
return False
except Exception:
print(f"make_connection - {traceback.format_exc()}")
I'm still fairly new to python and particularly networking, so I suspect I have made a rookie error. But so far all my searches have returned the obvious, that the TLS version is wrong, but the fact that it authenticates fine on the initial connection suggests to me that that isn't the case.
I'm happy to answer any questions I can about the situation.

Related

Python - [Errno 111] Connection refused on client side of the connection

I'm trying to create a chat between client and server written in Python, using SSL protocols with mutual authentication (i.e: server authenticates client and client authenticates server using certificates). My host machine is being used as the server, and my laptop is the client.
When attempting to connect to my host ip, I keep getting this error on my laptop:
Traceback (most recent call last):
File "/home/icarus/Codes/RealtimeChat/Chat.py", line 88, in <module>
main()
File "/home/icarus/Codes/RealtimeChat/Chat.py", line 75, in main
connection(ip, port, SSLSock)
File "/home/icarus/Codes/RealtimeChat/Chat.py", line 35, in connection
sock.connect((ip, port))
File "/usr/lib/python3.10/ssl.py", line 1375, in connect
self._real_connect(addr, False)
File "/usr/lib/python3.10/ssl.py", line 1362, in _real_connect
super().connect(addr)
ConnectionRefusedError: [Errno 111] Connection refused
And in the server - which was supposed to print a message saying that a connection was refused - nothing happens, it keeps listening for connections as if nothing happened
Connection function on client side:
def connection(ip, port, sock):
try:
sock.connect((ip, port))
print(f"Connected with {ip}")
except Exception as e:
print("Connection failed: ", e)
sock.close()
Server side:
def acceptConnection(self):
while True:
con, senderIP = self.sock.accept()
# Attempting to wrap connection with SSL socket
try:
SSLSock = self.getSSLSocket(con)
# If exception occurs, close socket and continue listening
except Exception as e:
print("Connection refused: ", e)
con.close()
continue
print(f"{senderIP} connected to the server")
# Adding connection to clients list
self.clients.append(SSLSock)
# Initializing thread to receive and communicate messages
# to all clients
threading.Thread(target=self.clientCommunication, args=(SSLSock, ), daemon=True).start()
This is the main function on my server:
def main():
serverIP = "127.0.0.1"
port = int(input("Port to listen for connections: "))
server = Server()
server.bindSocket(serverIP, port)
server.socketListen(2)
server.acceptConnection()
Everything works fine when I connect from my localhost (e.g I open a server on my host machine on one terminal and use another one on the same machine to connect to it). Both machines have the required certificates to authenticate each other, so I don't think that's the problem. Also, without the SSL implementation, the connection between this two different computers was refused by the server
I've tried using sock.bind('', port) on server side, disabling my firewall, used telnet 127.0.0.1 54321 (on my host machine) to check if the connection was working on the specified port (and it is), and also on the client machine (which showed that the connection was refused). I also tried running both scripts with admin privileges (sudo), but it also didn't work. Any suggestions?
I found what was wrong: I was trying to connect to my public IP address (which I found by searching for "What is my ip" on Google), but instead what should be done is to connect to the private IP address (I guess that's the correct name), and you can see yours using ifconfig on Linux and Mac and ipconfig on Windows using a terminal. By doing this, I could connect two computers that are on my network to my desktop server, I still haven't tested for computers in different networks, but the problem has been solved.

simple socket programming exercise for TCP connections in Python; Error: "No connection could be made because the target machine actively refused it"

*Before you mark as duplicate please note that I am referencing this similar question found here:
Python Socket Programming - ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it
unfortunately but have found anything in that post that provides a solution to my problem.
I am working on a very basic exercise designed to familiarize students with programming related to networks. This particular assignment is a common one as is described as follows:
In this assignment, you will learn the basics of socket programming for TCP connections in Python: how to create a socket, bind it to a specific address and port, as well as send and receive an HTTP packet. You will also learn some basics of HTTP header format. You can only use Python3.
You will develop a web server that handles one HTTP request at a time. Your web server should accept and parse the HTTP request, get the requested file from the server’s file system, create an HTTP response message consisting of the requested file preceded by header lines, and then send the response directly to the client. If the requested file is not present in the server, the server should send an HTTP “404 Not Found” message back to the client.
Part one specification:
Put the attached HTML file (named HelloWorld.html) in the same directory in which the server webserver.py runs. Run the server program. Determine the IP address of the host that is running the server (e.g., 128.238.251.26 or localhost). From another host, open a browser and provide the corresponding URL. For example: http://128.238.251.26:6789/HelloWorld.html. You can open a browser in the same host where the server runs and use the following http://localhost:6789/HelloWorld.html.
‘HelloWorld.html’ is the name of the file you placed in the server directory. Note also the use of the port number after the colon. You need to replace this port number with the port number that was assigned to you. In the above example, we have used port number 6789. The browser should then display the contents of HelloWorld.html. If you omit “:6789”, the browser will assume port 80 (why?), and you will get the web page from the server only if your server is listening at port 80.
Then try to get a file that is not present on the server (e.g., test.html). You should get a “404 File Not Found” message.
Part Two specification:
Write your own HTTP client to test your server. Your client will connect to the server using a TCP connection, send an HTTP request to the server, and display the server response as an output. You can assume that the HTTP request sent is a GET method. The client should take command line arguments specifying the server IP address or hostname, the port at which the server is listening, and the HTTP file name (e.g., test.html or HelloWorld.html). The following is an input command format to run the client. webclient.py <server_host> <server_port>
My code is for the Webserver is as follows:
#import socket module
from socket import *
import sys # In order to terminate the program
serverSocket = socket(AF_INET, SOCK_STREAM)
# Prepare a sever socket
# Fill in start
serverHost = '192.168.1.4'
serverPort = 56014
serverSocket.bind((serverHost, serverPort))
serverSocket.listen(5)
# Fill in end
while True:
#establish connection
print('The server is ready to receive')
connectionSocket, addr = serverSocket.accept() # Fill in start #Fill in end
try:
message = connectionSocket.recv(4096) # Fill in start #Fill in end
filename = message.split()[1]
f = open(filename[1:])
outputdata = f.readlines() # Fill in start #Fill in end
# send one http header line in to the socket
# Fill in start
connectionSocket.send("HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n")
connectionSocket.send("\r\n")
# Fill in end
# Send the content of the requested file to the connection socket
for i in range(0, len(outputdata)):
connectionSocket.send(outputdata[i].encode())
connectionSocket.send("\r\n".encode())
connectionSocket.close()
except IOError:
# Send HTTP response code and message for file not found
# Fill in start
connectionSocket.send("HTTP/1.1 404 Not Found\r\n")
connectionSocket.send("Content-Type: text/html\r\n")
connectionSocket.send("\r\n")
connectionSocket.send("<html><head></head><body><h1>404 Not Found</h1></body></html><\r\n>")
# Fill in end
# Close the client connection socket
# Fill in start
serverSocket.close()
# Fill in end
serverSocket.close()
sys.exit() # Terminate the program after sending the corresponding data
My code for the Webclient is as follows:
from socket import *
import sys
serverName = sys.argv[1]
serverPort = int(sys.argv[2])
fileName = sys.argv[3]
request = "GET "+str(fileName)+" HTTP/1.1"
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((serverName, serverPort))
clientSocket.send(request.encode())
returnFromSever = clientSocket.recv(4096)
while(len(returnFromSever)>0):
print(returnFromSever.decode())
returnFromSever = clientSocket.recv(4096)
clientSocket.close()
The error I am receiving is:
"No connection could be made because the target machine actively refused it"
Admittedly, I know almost nothing about network related programming and on top of that I am not familiar with the Python syntax (my entire degree program was exclusively in Java) so I am very lost here and somewhat desperate.
If anyone could please point me in the right direction as far as how to correct this error, I would be very deeply grateful.
Thanks
The error you are getting (No connection could be made because the target machine actively refused it) means that the port you are trying to connect to is not not being listened on the server.
For example, if you try to connect to 192.168.1.1:80 (IP = 192.168.1.1, port=80) and the server on 192.168.1.1 doesn't listen on port 80, you would receive this error.
A few things I would check in your case:
Is your server IP actually 192.168.1.4 ? If not, set it to the correct IP of the interface you want to listen on. If you want to listen on all the interfaces of the server, use this: serverHost = '0.0.0.0'
Does your client code attempt to connect to the server port? The server port is 56014. You need to pass it as the second parameter of your client program (because of this line serverPort = int(sys.argv[2])).

WinError 10060 Error when trying to connect to remote server using Python PySFTP module

I am trying to connect to a remote server and list files inside a path using the below code:
import pysftp
myHostname = "myhostname.com"
myPort = <someportnumber>
myUsername = "<valid username>"
myPassword = "<valid password>"
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
with pysftp.Connection(host=myHostname, username=myUsername, password=myPassword, cnopts= cnopts, port=myPort) as sftp:
print("Connection succesfully established ... ")
sftp.chdir('/logs/dev')
# Obtain structure of the remote directory
directory_structure = sftp.listdir_attr()
# Print data
for attr in directory_structure:
print(attr.filename, attr)
But when I am running it, It is unable to establish a connection. It's throwing below exception:
Traceback (most recent call last):
File "c:/Users/611841191/Documents/SFTP File Download/SFTPFileDownload.py", line 11, in <module>
with pysftp.Connection(host=myHostname, username=myUsername, password=myPassword, cnopts= cnopts, port=myPort) as sftp:
File "C:\Users\611841191\AppData\Roaming\Python\Python38\site-packages\pysftp\__init__.py", line 140, in __init__
self._start_transport(host, port)
File "C:\Users\611841191\AppData\Roaming\Python\Python38\site-packages\pysftp\__init__.py", line 176, in _start_transport
self._transport = paramiko.Transport((host, port))
File "C:\Users\611841191\AppData\Roaming\Python\Python38\site-packages\paramiko\transport.py", line 415, in __init__
raise SSHException(
paramiko.ssh_exception.SSHException: Unable to connect to <myhostname.com>: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time or established connection failed because connected host has failed to respond
Can anyone help me out with why this exception is being thrown because I tried with other remote servers and the code seems to be working fine for them? The code is throwing exception for one particular remote server only.
If your code cannot connect somewhere using some protocol (SFTP in this case), the first thing to test is, whether you can connect using the same protocol using any existing GUI/commandline client from the same machine that runs your code.
If that does not work either, you do not have a programming question, but a simple network connectivity problem.
If you need a help resolving the problem, please go to Super User or Server Fault.

Python 3.8 TLSv1.3 socket close result in ConnectionResetError or ConnectionAbortedError

Client side:
data = b'\xff' * 1000000
ssock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
#context is created by ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
ssock = context.wrap_socket(ssock, server_hostname='xd1337sv')
ssock.connect((SERVERADDR, SERVERPORT))
ssock.sendall(data)
#time.sleep(3)
ssock.close()
If I just use regular non-SSL socket, everything works correctly with the server receiving exact amount of data. If I use TLS socket, the behavior then depends on the version.
If I run either the server or client on Python 3.6 and therefore the TLSv1.2 will be used, there's no problem.
Problem arises only when TLSv1.3 is used and depends on the size of data and how soon client ssocket.close() line is executed.
If I put a right amount of time.sleep before ssocket.close() depending on the size of data, then I get no error. Otherwise, the server will get ConnectionResetError [WinError 10054] An existing connection was forcibly closed by the remote host and receive only part of the data, or throw ConnectionAbortedError [WinError 10053] An established connection was aborted by the software in your host machine and receive no data.
I'm testing both the server and client on my local machine with local address 192.168.1.2.
The difference is caused by TLS 1.3 sending a session ticket after the TLS handshake while with previous TLS versions the session ticket is send inside the TLS handshake. Thus, with TLS 1.3 data from the server (the session ticket) will arrive after the ssock.connect(...) is done. Since your application does not read any data after the connect it closes the socket while unread data are still inside the socket buffer of the underlying TCP socket. This will cause RST send to the server and cause there the connection reset error.
This is a known problems with applications which never attempt to read from the server. If the application would expect a response from the server and use recv to get it this would implicitly also read the session ticket.
To fix this situation when you don't expect the server to return any application data do a proper SSL shutdown of the socket before closing it. Since this will read the servers SSL shutdown message it will also implicitly read the session ticket send before by the server.
try:
ssock = ssock.unwrap()
except:
True
ssock.close()
For more information see also this issue and this documentation.
I was getting a similar problem when the application was running through gunicorn with certificates. The jsondecodeerror problem randomly came to the client, i.e. the response was empty. The only thing that TLS 1.2 was used.
The solution was simple, I deployed the application on uwsgi and the problem went away

SSL Certificate Verify Failed on python mqtt connection

I am a having a very strange issue. The premise is that I am fairly ignorant in both mqtt and python (the latter I don't use it now since at least 5-6 years), but I am making a Unity app for a museum using a 3D tracking system (www.pozyx.io) and I need each of my machines to run a small mqtt-to-OSC client, so that my Unity app can read the position data from the client.
On my development machine, it all works like a charm, using a slightly modified version of the script provided by the sensor producer.
`
API_KEY = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
import paho.mqtt.client as mqtt
import ssl
import json
from pythonosc.udp_client import SimpleUDPClient
host = "mqtt.cloud.pozyxlabs.com"
port = 443
topic = "5c500595601a3f5871a17685"
username = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
password = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
ip = "127.0.0.1" # IP for the OSC UDP
network_port = 8888 # network port for the OSC UDP
osc_udp_client = SimpleUDPClient(ip, network_port)
def on_connect(client, userdata, flags, rc):
print(mqtt.connack_string(rc))
def on_message(client, userdata, msg):
tag_data = json.loads(msg.payload.decode())
for tag in tag_data:
try:
network_id = tag["tagId"]
#print(network_id)
timestamp = tag["timestamp"]
position = tag["data"]["coordinates"]
yaw = tag["data"]["orientation"]["yaw"]
osc_udp_client.send_message("/position", [network_id, timestamp, position["x"], position["y"], position["z"], yaw])
except:
print("Received a bad packet?")
pass
def on_subscribe(client, userdata, mid, granted_qos):
print("Subscribed to topic!")
client = mqtt.Client(transport="websockets")
client.username_pw_set(username, password=password)
client.tls_set_context(context=ssl.create_default_context())
client.on_connect = on_connect
client.on_message = on_message
client.on_subscribe = on_subscribe
client.connect(host, port=port)
client.subscribe(topic)
client.loop_forever()
`
Now that I am in the musem to deploy, of course on the freshly setup windows 10 machines ( I tried both on a NUC and and on a Lenovo Thinkpad), nothing works, and I get each time the following error
C:\Users\Vattenkikare1\Desktop\osc_hans>py osc_hans.py
Traceback (most recent call last):
File "osc_hans.py", line 67, in
client.connect(host, port=port)
File "C:\Users\Vattenkikare1\AppData\Local\Programs\Python\Python37-32\lib\site-packages\paho\mqtt\client.py", line 839, in connect
return self.reconnect()
File "C:\Users\Vattenkikare1\AppData\Local\Programs\Python\Python37-32\lib\site-packages\paho\mqtt\client.py", line 994, in reconnect
sock.do_handshake()
File "C:\Users\Vattenkikare1\AppData\Local\Programs\Python\Python37-32\lib\ssl.py", line 1117, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)
My laptop is plugged onto the same WiFi and I do have admin rights on all the machines. Would you have any idea on what might be causing the problem? And why might that happen only on the other computers and not on mine?
I did first deploy an exe to those machines, but then on one of them i did a quick python setup with all the modules, but nothing changed.
I did find a few similar issues around, but none that I could relate directly to mine in terms of solution.
I seem to have found the solution in the most random way. I noticed on a post that the Pozyx.io website used the "COMODO RSA Domain Validation Secure Server CA" certificate, and even though the API documentation didn't mention it, I installed it on the test computers and all started working.

Categories