Is there any working example of websocket client on bluemix?
I tried a lot of examples which was found in Github but it is not working. The server is created using node red and an HTML instance is able to communicate with node red server. But, python is not able to communicate.
Here is my code:
ws = create_connection("host name")
print "Sending 'Hello, World'..."
ws.send("Hello, World")
print "Sent"
print "Receiving..."
result = ws.recv()
print "Received '%s'" % result
In the above example, hand shake fails during create connection. I tried many other examples available on internet, but none of them are working.
Edit: Adding more details on handshake problem:
DEBUG:root:--- request header ---
DEBUG:root:GET /ws/Test HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Host: tryandbuyoncloud.stage1.mybluemix.net
Origin: tryandbuyoncloud.stage1.mybluemix.net
Sec-WebSocket-Key1: 2 0{mN6 9 532X59 5V
Sec-WebSocket-Key2: } pp2B054402V # _-5S8O0 kX
e�8��ۨ-
DEBUG:root:-----------------------
DEBUG:root:--- response header ---
DEBUG:root:HTTP/1.1 500 Error
DEBUG:root:Content-Type: text/plain; charset=UTF-8
DEBUG:root:X-Backside-Transport: FAIL FAIL
DEBUG:root:Connection: close
More details:
487 ws = create_connection("ws://tryandbuyoncloud.stage1.mybluemix.net/ws/Test")
488 print "Sending 'Hello, World'..."
489 ws.send("Hello, World")
<ipython-input-96-f14c8986ac30> in create_connection(url, timeout, **options)
86 websock = WebSocket()
87 websock.settimeout(timeout != None and timeout or default_timeout)
---> 88 websock.connect(url, **options)
89 return websock
90
<ipython-input-96-f14c8986ac30> in connect(self, url, **options)
186 if is_secure:
187 self.io_sock = _SSLSocketWrapper(self.sock)
--> 188 self._handshake(hostname, port, resource, **options)
189
190 def _handshake(self, host, port, resource, **options):
<ipython-input-96-f14c8986ac30> in _handshake(self, host, port, resource, **options)
222 if status != 101:
223 self.close()
--> 224 raise WebSocketException("Handshake Status %d" % status)
225 success, secure = self._validate_header(resp_headers)
226 if not success:
WebSocketException: Handshake Status 500
Related
I have a problem with making a call using the PJSUA2 api for python, and that is that when receiving the 407 authorization request is not responded to from PJSIP.
Eventhough it says that the request is begin sent in the console from PJSIP, it doesnt actually sent anything when looking at it with Wireshark.
I have no warnings or errors indicating something going wrong. The log is filled with PJSIP trying to make the INVITE request with authorization but doesn't get a response because it probably isn't actually sent.
What is happening and how can I fix it?
The 407 response:
13:01:03.043 tsx0x1fd1228 ....Temporary failure in sending Request msg INVITE/cseq=21903 (tdta0x1fce0a8), will try next server: Unsupported transport (PJSIP_EUNSUPTRANSPORT)
13:01:03.043 pjsua_core.c ....TX 1427 bytes Request msg INVITE/cseq=21903 (tdta0x1fce0a8) to UDP 192.168.2.16:5080:
INVITE sip:+316xxxxxxxx#192.168.2.16:5080 SIP/2.0
Via: SIP/2.0/UDP 192.168.2.11:57880;rport;branch=z9hG4bKPj1cd4c855-e407-4620-af0b-d245aeab2132
Max-Forwards: 70
From: <sip:1010#192.168.2.16>;tag=e7cf4af1-bb8e-4d59-8d79-5050118e9bd5
To: <sip:+316xxxxxxxx#192.168.2.16>
Contact: <sip:1010#192.168.2.11:57880;ob>
Call-ID: 7c17cb03-7833-4a0d-95be-1085ab6ce2ff
CSeq: 21903 INVITE
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Supported: replaces, 100rel, timer, norefersub
Session-Expires: 1800
Min-SE: 90
Content-Type: application/sdp
Content-Length: 806
v=0
o=- 3884587263 3884587263 IN IP4 172.22.178.52
s=pjmedia
b=AS:117
t=0 0
a=X-nat:0
m=audio 4000 RTP/AVP 8 0 9 96 97 98 99 3 100 101 102 120 121 122 123
c=IN IP4 172.22.178.52
b=TIAS:96000
a=rtcp:4001 IN IP4 172.22.178.52
a=sendrecv
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:9 G722/8000
a=rtpmap:96 iLBC/8000
a=fmtp:96 mode=30
a=rtpmap:97 speex/8000
a=rtpmap:98 speex/16000
a=rtpmap:99 speex/32000
a=rtpmap:3 GSM/8000
a=rtpmap:100 AMR/8000
a=rtpmap:101 AMR-WB/16000
a=rtpmap:102 opus/48000/2
a=fmtp:102 useinbandfec=1
a=rtpmap:120 telephone-event/8000
a=fmtp:120 0-16
a=rtpmap:121 telephone-event/16000
a=fmtp:121 0-16
a=rtpmap:122 telephone-event/32000
a=fmtp:122 0-16
a=rtpmap:123 telephone-event/48000
a=fmtp:123 0-16
a=ssrc:1026369925 cname:0a2ee5815d3913eb
--end msg--
13:01:03.057 pjsua_core.c .RX 693 bytes Response msg 407/INVITE/cseq=21903 (rdata0x1fa9088) from UDP 192.168.2.16:5080:
SIP/2.0 407 Proxy Authentication Required
Via: SIP/2.0/UDP 192.168.2.11:57880;rport=57880;branch=z9hG4bKPj1cd4c855-e407-4620-af0b-d245aeab2132
From: <sip:1010#192.168.2.16>;tag=e7cf4af1-bb8e-4d59-8d79-5050118e9bd5
To: <sip:+316xxxxxxxx#192.168.2.16>;tag=4SXQa24prg6rg
Call-ID: 7c17cb03-7833-4a0d-95be-1085ab6ce2ff
CSeq: 21903 INVITE
User-Agent: FreeSWITCH
Accept: application/sdp
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY
Supported: path, replaces
Allow-Events: talk, hold, conference, refer
Proxy-Authenticate: Digest realm="192.168.2.16", nonce="1e8bd613-7ac0-4516-bbeb-4778ef103ed7", algorithm=MD5, qop="auth"
Content-Length: 0
--end msg--
13:01:03.057 pjsua_core.c ..TX 375 bytes Request msg ACK/cseq=21903 (tdta0x7fdc68000c08) to UDP 192.168.2.16:5080:
ACK sip:+316xxxxxxxx#192.168.2.16:5080 SIP/2.0
Via: SIP/2.0/UDP 192.168.2.11:57880;rport;branch=z9hG4bKPj1cd4c855-e407-4620-af0b-d245aeab2132
Max-Forwards: 70
From: <sip:1010#192.168.2.16>;tag=e7cf4af1-bb8e-4d59-8d79-5050118e9bd5
To: <sip:+316xxxxxxxx#192.168.2.16>;tag=4SXQa24prg6rg
Call-ID: 7c17cb03-7833-4a0d-95be-1085ab6ce2ff
CSeq: 21903 ACK
Content-Length: 0
The "sent" request:
13:01:03.057 pjsua_core.c .......TX 1708 bytes Request msg INVITE/cseq=21904 (tdta0x1fce0a8) to UDP 192.168.2.16:5080:
INVITE sip:+316xxxxxxxx#192.168.2.16:5080 SIP/2.0
Via: SIP/2.0/UDP 192.168.2.11:57880;rport;branch=z9hG4bKPjbd8dbeef-81d0-4f0d-9e07-8e1526c3109f
Max-Forwards: 70
From: <sip:1010#192.168.2.16>;tag=e7cf4af1-bb8e-4d59-8d79-5050118e9bd5
To: <sip:+316xxxxxxxx#192.168.2.16>
Contact: <sip:1010#192.168.2.11:57880;ob>
Call-ID: 7c17cb03-7833-4a0d-95be-1085ab6ce2ff
CSeq: 21904 INVITE
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Supported: replaces, 100rel, timer, norefersub
Session-Expires: 1800
Min-SE: 90
Proxy-Authorization: Digest username="1010", realm="192.168.2.16", nonce="1e8bd613-7ac0-4516-bbeb-4778ef103ed7", uri="sip:+316xxxxxxxx#192.168.2.16:5080", response="4e640a090416645a11c6a6198fe4d523", algorithm=MD5, cnonce="5b5c5283ae234889ba31abc34b7f0a4e", qop=auth, nc=00000001
Content-Type: application/sdp
Content-Length: 806
v=0
o=- 3884587263 3884587263 IN IP4 172.22.178.52
s=pjmedia
b=AS:117
t=0 0
a=X-nat:0
m=audio 4000 RTP/AVP 8 0 9 96 97 98 99 3 100 101 102 120 121 122 123
c=IN IP4 172.22.178.52
b=TIAS:96000
a=rtcp:4001 IN IP4 172.22.178.52
a=sendrecv
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:9 G722/8000
a=rtpmap:96 iLBC/8000
a=fmtp:96 mode=30
a=rtpmap:97 speex/8000
a=rtpmap:98 speex/16000
a=rtpmap:99 speex/32000
a=rtpmap:3 GSM/8000
a=rtpmap:100 AMR/8000
a=rtpmap:101 AMR-WB/16000
a=rtpmap:102 opus/48000/2
a=fmtp:102 useinbandfec=1
a=rtpmap:120 telephone-event/8000
a=fmtp:120 0-16
a=rtpmap:121 telephone-event/16000
a=fmtp:121 0-16
a=rtpmap:122 telephone-event/32000
a=fmtp:122 0-16
a=rtpmap:123 telephone-event/48000
a=fmtp:123 0-16
a=ssrc:1026369925 cname:0a2ee5815d3913eb
The flow sequence:
Wireshark flow sequence
I'm trying to write a simple SIP agent to receive a call using PJSUA2 python swig module, but can't see how this swig module works. I've got the following code
import pjsua2 as pj
import time
class Endpoint(pj.Endpoint):
"""
This is high level Python object inherited from pj.Endpoint
"""
instance = None
def __init__(self):
pj.Endpoint.__init__(self)
Endpoint.instance = self
def validateUri(uri):
return Endpoint.instance.utilVerifyUri(uri) == pj.PJ_SUCCESS
def validateSipUri(uri):
return Endpoint.instance.utilVerifySipUri(uri) == pj.PJ_SUCCESS
# Call class
class Call(pj.Call):
"""
High level Python Call object, derived from pjsua2's Call object.
"""
def __init__(self, acc, peer_uri='', call_id=pj.PJSUA_INVALID_ID):
pj.Call.__init__(self, acc, call_id)
self.acc = acc
self.peerUri = peer_uri
self.connected = False
self.onhold = False
def onCallState(self, prm):
ci = self.getInfo()
self.connected = ci.state == pj.PJSIP_INV_STATE_CONFIRMED
def onCallMediaState(self, prm):
ci = self.getInfo()
for mi in ci.media:
if mi.type == pj.PJMEDIA_TYPE_AUDIO and \
(mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE or
mi.status == pj.PJSUA_CALL_MEDIA_REMOTE_HOLD):
m = self.getMedia(mi.index)
am = pj.AudioMedia.typecastFromMedia(m)
# connect ports
Endpoint.instance.audDevManager().getCaptureDevMedia().startTransmit(am)
am.startTransmit(Endpoint.instance.audDevManager().getPlaybackDevMedia())
if mi.status == pj.PJSUA_CALL_MEDIA_REMOTE_HOLD and not self.onhold:
print("'%s' sets call onhold" % self.peerUri)
self.onhold = True
elif mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE and self.onhold:
print("'%s' sets call active" % self.peerUri)
self.onhold = False
def onDtmfDigit(self, prm):
# print("Got DTMF:" + prm.digit)
pass
def onCallMediaTransportState(self, prm):
# print("Media transport state")
pass
class Account(pj.Account):
def onRegState(self, prm):
print("***OnRegState: " + prm.reason)
def onMwiInfo(self, prm):
print("OnMwiState: " + prm.reason)
def onBuddyState(self, prm):
print("OnBuddyState: " + prm.reason)
def onIncommingSubscribe(self, prm):
print("OnSubscribeState: " + prm.reason)
def OnIncomingCall(self, prm):
c = Call(self, call_id=prm.callId)
call_prm = pj.CallOpParam()
call_prm.statusCode = 180
c.answer(call_prm)
ci = c.getInfo()
if input(f"Accept call from {ci.remoteUri}?") == u'yes':
call_prm.statusCode = 200
c.answer(call_prm)
else:
c.hangup(call_prm)
def initalise_sip_stack():
ep_cfg = pj.EpConfig()
ep = Endpoint()
ep.libCreate()
ep.libInit(ep_cfg)
sip_tp_config = pj.TransportConfig()
sip_tp_config.port = 5060
ep.transportCreate(pj.PJSIP_TRANSPORT_UDP, sip_tp_config)
ep.libStart()
acfg = pj.AccountConfig()
acfg.idUri = "sip:056004#172.20.1.8"
acfg.regConfig.registrarUri = "sip:172.20.1.8"
creds = pj.AuthCredInfo("digest", "*", "056004", 0, "somepass")
acfg.sipConfig.authCreds.append(creds)
acc = Account()
acc.create(acfg)
return ep
if __name__ == "__main__":
endpoint = initalise_sip_stack()
time.sleep(600)
endpoint.libDestroy()
This little client is able to register in my asterisk server as you can see
raspberrypi*CLI> pjsip show contacts
Contact: <Aor/ContactUri..............................> <Hash....> <Status> <RTT(ms)..>
==========================================================================================
Contact: 056003/sip:056003#172.20.1.13:5060 058bca1427 Avail 41.057
Contact: 056004/sip:056004#172.20.1.2:5060;ob e8ff0c4e2b Avail 2.358
Objects found: 2
However, when I place a call from 056003 contact, I can see the following trace from pjsua2:
16:52:37.918 pjsua_core.c .RX 947 bytes Request msg INVITE/cseq=23923 (rdata0x7f5f6c001c48) from UDP 172.20.1.8:5060:
INVITE sip:056004#172.20.1.2:5060;ob SIP/2.0
Via: SIP/2.0/UDP 0.0.0.0:5060;rport;branch=z9hG4bKPjada6202d-813b-499c-9b5c-2ad5abf6706e
From: "MI 3" <sip:056003#172.20.1.8>;tag=91efaf53-e6fb-45dc-b2d4-ddc99a6c3c36
To: <sip:056004#172.20.1.2;ob>
Contact: <sip:056003#0.0.0.0:5060>
Call-ID: 1bf35bec-1a88-468e-bd17-dfa99086c457
CSeq: 23923 INVITE
Allow: OPTIONS, REGISTER, SUBSCRIBE, NOTIFY, PUBLISH, INVITE, ACK, BYE, CANCEL, UPDATE, PRACK, MESSAGE, REFER
Supported: 100rel, timer, replaces, norefersub, histinfo
Session-Expires: 1800
Min-SE: 90
P-Asserted-Identity: "MI 3" <sip:056003#172.20.1.8>
Max-Forwards: 70
User-Agent: FPBX-15.0.23(16.16.1)
Content-Type: application/sdp
Content-Length: 231
v=0
o=- 519853527 519853527 IN IP4 172.20.1.8
s=Asterisk
c=IN IP4 172.20.1.8
t=0 0
m=audio 14490 RTP/AVP 9 101
a=rtpmap:9 G722/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ptime:20
a=maxptime:150
a=sendrecv
--end msg--
16:52:37.918 pjsua_call.c .Incoming Request msg INVITE/cseq=23923 (rdata0x7f5f6c001c48)
16:52:37.919 pjsua_acc.c ..No available account to handle Request msg INVITE/cseq=23923 (rdata0x7f5f6c001c48)
16:52:37.919 pjsua_core.c ..TX 402 bytes Response msg 480/INVITE/cseq=23923 (tdta0x7f5f6c006b78) to UDP 172.20.1.8:5060:
SIP/2.0 480 Temporarily Unavailable
Via: SIP/2.0/UDP 0.0.0.0:5060;rport=5060;received=172.20.1.8;branch=z9hG4bKPjada6202d-813b-499c-9b5c-2ad5abf6706e
Call-ID: 1bf35bec-1a88-468e-bd17-dfa99086c457
From: "MI 3" <sip:056003#172.20.1.8>;tag=91efaf53-e6fb-45dc-b2d4-ddc99a6c3c36
To: <sip:056004#172.20.1.2;ob>;tag=z9hG4bKPjada6202d-813b-499c-9b5c-2ad5abf6706e
CSeq: 23923 INVITE
Content-Length: 0
--end msg--
16:52:37.919 pjsua_call.c ..Unable to accept incoming call (no available account)
16:52:37.921 pjsua_core.c .RX 433 bytes Request msg ACK/cseq=23923 (rdata0x7f5f6c001c48) from UDP 172.20.1.8:5060:
ACK sip:056004#172.20.1.2:5060;ob SIP/2.0
Via: SIP/2.0/UDP 0.0.0.0:5060;rport;branch=z9hG4bKPjada6202d-813b-499c-9b5c-2ad5abf6706e
From: "MI 3" <sip:056003#172.20.1.8>;tag=91efaf53-e6fb-45dc-b2d4-ddc99a6c3c36
To: <sip:056004#172.20.1.2;ob>;tag=z9hG4bKPjada6202d-813b-499c-9b5c-2ad5abf6706e
Call-ID: 1bf35bec-1a88-468e-bd17-dfa99086c457
CSeq: 23923 ACK
Max-Forwards: 70
User-Agent: FPBX-15.0.23(16.16.1)
Content-Length: 0
--end msg--
16:52:41.382 pjsua_core.c .RX 419 bytes Request msg OPTIONS/cseq=9130 (rdata0x7f5f6c001c48) from UDP 172.20.1.8:5060:
OPTIONS sip:056004#172.20.1.2:5060;ob SIP/2.0
Via: SIP/2.0/UDP 0.0.0.0:5060;rport;branch=z9hG4bKPj54cf9751-5357-4887-91d3-b8d97ea6d2f4
From: <sip:056004#172.20.1.8>;tag=9a799201-1424-418d-b5c4-44997fc40829
To: <sip:056004#172.20.1.2;ob>
Contact: <sip:056004#0.0.0.0:5060>
Call-ID: 84c421ff-ae98-475f-b11e-ac7cd27caa66
CSeq: 9130 OPTIONS
Max-Forwards: 70
User-Agent: FPBX-15.0.23(16.16.1)
Content-Length: 0
--end msg--
16:52:41.382 pjsua_core.c .TX 760 bytes Response msg 200/OPTIONS/cseq=9130 (tdta0x7f5f6c003c18) to UDP 172.20.1.8:5060:
SIP/2.0 200 OK
Via: SIP/2.0/UDP 0.0.0.0:5060;rport=5060;received=172.20.1.8;branch=z9hG4bKPj54cf9751-5357-4887-91d3-b8d97ea6d2f4
Call-ID: 84c421ff-ae98-475f-b11e-ac7cd27caa66
From: <sip:056004#172.20.1.8>;tag=9a799201-1424-418d-b5c4-44997fc40829
To: <sip:056004#172.20.1.2;ob>;tag=z9hG4bKPj54cf9751-5357-4887-91d3-b8d97ea6d2f4
CSeq: 9130 OPTIONS
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Accept: application/sdp, application/pidf+xml, application/xpidf+xml, application/simple-message-summary, message/sipfrag;version=2.0, application/im-iscomposing+xml, text/plain
Supported: replaces, 100rel, timer, norefersub, trickle-ice
Allow-Events: presence, message-summary, refer
Content-Length: 0
--end msg--
And not sure why it says pjsua_acc.c ..No available account to handle Request msg INVITE/cseq=23923 (rdata0x7f5f6c001c48)
Some idea? what part is bad implemented in my code? Maybe should I handle the initalise_sip_stack() function as a thread/process?
Thank you very much!
Currently I'm trying to develop a simple UDP DTLS server using pre shared keys on Ubuntu 20.04, to receive UDP datagrams from an embedded application.
My remote example echo server based on python-mbedtls correctly echoes messages from a python-mbedtls client used for testing, but fails to verify the message MAC during the handshake with an openssl command line s_client. It similarly fails to verify the MAC of my embedded DTLS client, even though that is correctly sending messages to a command line openssl s_server. These are all using the same pre-shared keys and client-identity.
Ideas on why MAC verification might be failing would be appreciated, or suggestions for diagnostics. There's not a lot that's useful in the debug outputs so far.
Here is my server code:
#!/home/ron/venvs/udpserver/bin/python3
"""Example DTLS server"""
import sys
import time
from contextlib import suppress
from functools import partial
from typing import Any, Callable, NoReturn, Optional, Tuple, Union
import datetime as dt
import socket
import struct
from mbedtls.pk import RSA, ECC
from mbedtls.x509 import BasicConstraints, CRT, CSR
from mbedtls.tls import *
from mbedtls._tls import _enable_debug_output, _set_debug_level # type: ignore
from mbedtls.tls import (
DTLSConfiguration,
HelloVerifyRequest,
ServerContext,
TLSWrappedSocket,
)
conf = DTLSConfiguration(
ciphers=(
"TLS-PSK-WITH-AES-256-CBC-SHA",
"TLS-ECDHE-PSK-WITH-CHACHA20-POLY1305-SHA256",
"TLS-RSA-PSK-WITH-CHACHA20-POLY1305-SHA256"
),
pre_shared_key=('Client_identity',b'010102030405060708090a0b0c0d0e0f'),
validate_certificates=False
)
print("conf: {}".format(conf))
_enable_debug_output(conf)
_set_debug_level(3)
def echo_until(sock, end):
cli0, cli_address0 = sock.accept()
cli0.setcookieparam(cli_address0[0].encode("ascii"))
print("cli_address0: {}".format(cli_address0))
try:
# block(cli0.do_handshake)
cli0.do_handshake()
except HelloVerifyRequest:
print("HVR")
cli1, cli_address1 = cli0.accept()
cli0.close()
cli1.setcookieparam(cli_address1[0].encode("ascii"))
print("cli_address1: {}".format(cli_address1))
# block(cli1.do_handshake)
cli1.do_handshake()
print(" .", "handshake", cli1.negotiated_tls_version())
cli = cli1
while True:
# data = block(cli.recv, 4096)
data = cli.recv(4096)
print(" .", "R", data)
# nn = block(cli.send, data)
nn = cli.send(data)
print(" .", "S", nn, len(data))
if data == end:
break
print(" .", "done")
print(cli)
cli.close()
address = ("0.0.0.0", 9009)
host, port = address
ctx = ServerContext(conf)
srv = ctx.wrap_socket(
socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print(" .", "bind", srv, address)
srv.bind(address)
while True:
print(" .", ">>>")
echo_until(srv, b"\0")
print(" .", "<<<")
and here is the client code that works:
#!/media/fred/venvs/dtlsclient/bin/python3
"""An example DTLS PSK client.
"""
from __future__ import annotations
import socket
import sys
import time
from contextlib import suppress
from typing import Any, Optional, Tuple, Union
from mbedtls._tls import _enable_debug_output, _set_debug_level # type: ignore
from mbedtls.exceptions import TLSError
from mbedtls.tls import (
ClientContext,
DTLSConfiguration,
TLSWrappedSocket,
)
if sys.version_info < (3, 10):
from typing_extensions import TypeAlias
else:
from typing import TypeAlias
if sys.version_info < (3, 8):
from typing_extensions import Final
else:
from typing import Final
def _echo_dtls(sock: TLSWrappedSocket, buffer: bytes, chunksize: int) -> bytes:
view = memoryview(buffer)
received = bytearray()
while len(received) != len(buffer):
part = view[len(received) : len(received) + chunksize]
sock.send(part)
data, _addr = sock.recvfrom(chunksize)
received += data
if not data:
# Avoid tight loop.
time.sleep(0.01)
return received
class Client:
def __init__(
self,
cli_conf: DTLSConfiguration,
proto: socket.SocketKind,
srv_address: _Address,
srv_hostname: Optional[str],
) -> None:
super().__init__()
self.cli_conf: Final = cli_conf
self.proto: Final = proto
self.srv_address: Final = srv_address
self.srv_hostname: Final = srv_hostname
self._sock: Optional[TLSWrappedSocket] = None
self._echo: Final = {
socket.SOCK_DGRAM: _echo_dtls,
}[self.proto]
def __enter__(self) -> Client:
self.start()
return self
def __exit__(self, *exc_info: object) -> None:
self.stop()
def __del__(self) -> None:
self.stop()
#property
def context(self) -> Optional[ClientContext]:
if self._sock is None:
return None
assert isinstance(self._sock.context, ClientContext)
return self._sock.context
def do_handshake(self) -> None:
if not self._sock:
return
self._sock.do_handshake()
def echo(self, buffer: bytes, chunksize: int) -> bytes:
if not self._sock:
return b""
return bytes(self._echo(self._sock, buffer, chunksize))
def start(self) -> None:
if self._sock:
self.stop()
self._sock = ClientContext(self.cli_conf).wrap_socket(
socket.socket(socket.AF_INET, self.proto),
server_hostname=self.srv_hostname,
)
self._sock.connect(self.srv_address)
def stop(self) -> None:
if not self._sock:
return
with suppress(TLSError, OSError):
self._sock.close()
self._sock = None
def restart(self) -> None:
self.stop()
self.start()
def main() -> None:
address = "149.28.170.96"
port = 9009
message = "Trundled off to the jungle"
server_name = "dtlsserver"
proto = socket.SOCK_DGRAM
debug = 3
conf = DTLSConfiguration(
ciphers=(
"TLS-PSK-WITH-AES-256-CBC-SHA",
"TLS-ECDHE-PSK-WITH-CHACHA20-POLY1305-SHA256",
"TLS-RSA-PSK-WITH-CHACHA20-POLY1305-SHA256"
),
pre_shared_key=('Client_identity',b'010102030405060708090a0b0c0d0e0f'),
validate_certificates=False
)
print(conf)
if debug is not None:
_enable_debug_output(conf)
_set_debug_level(debug)
with Client(
conf, proto, (address, port), server_name
) as cli:
cli.do_handshake()
received = cli.echo(message.encode("utf-8"), 1024)
print("Received:" + received.decode("utf-8"))
if __name__ == "__main__":
main( )
Whereas an openssl command line client invocation like this fails:
openssl s_client -psk "010102030405060708090a0b0c0d0e0f" -psk_identity "Client_identity" -dtls1_2 -port 9009 -host 149.28.170.96 -async -debug
This same call works ok with an openssl s_server running on the same remote Ubuntu server.
Here's a partial listing of debug text from the server showing the failure using the openssl client:
ssl_msg.c:3620: input record: msgtype = 22, version = [3:3], msglen = 68
ssl_msg.c:1131: => decrypt buf
ssl_msg.c:1342: using encrypt then mac
ssl_msg.c:1385: message mac does not match
ssl_msg.c:3755: ssl_decrypt_buf() returned -29056 (-0x7180)
ssl_msg.c:4921: => send alert message
ssl_msg.c:4922: send alert level=2 message=20
ssl_msg.c:2684: => write record
ssl_msg.c:2797: output record: msgtype = 21, version = [254:253], msglen = 2
ssl_msg.c:2087: => flush output
ssl_msg.c:2105: message length: 15, out_left: 15
ssl_msg.c:2112: ssl->f_send() returned 15 (-0xfffffff1)
ssl_msg.c:2140: <= flush output
ssl_msg.c:2853: <= write record
ssl_msg.c:4934: <= send alert message
ssl_msg.c:3917: ssl_get_next_record() returned -29056 (-0x7180)
ssl_tls.c:3650: mbedtls_ssl_read_record() returned -29056 (-0x7180)
ssl_msg.c:0072: set_timer to 0 ms
ssl_msg.c:0072: set_timer to 0 ms
Traceback (most recent call last):
File "/home/ron/venvs/udpserver/./dtlsthreaded.py", line 96, in <module>
echo_until(srv, b"\0")
File "/home/ron/venvs/udpserver/./dtlsthreaded.py", line 64, in echo_until
block(cli1.do_handshake)
File "/home/ron/venvs/udpserver/./dtlsthreaded.py", line 28, in block
result = cb(*args, **kwargs)
File "/home/ron/venvs/udpserver/lib/python3.10/site-packages/mbedtls/tls.py", line 341, in do_handshake
self._buffer.do_handshake()
File "src/mbedtls/_tls.pyx", line 1404, in mbedtls._tls.MbedTLSBuffer.do_handshake
File "src/mbedtls/_tls.pyx", line 1429, in mbedtls._tls.MbedTLSBuffer._handle_handshake_response
File "src/mbedtls/exceptions.pyx", line 53, in mbedtls.exceptions.check_error
File "src/mbedtls/exceptions.pyx", line 56, in mbedtls.exceptions.check_error
mbedtls.exceptions.TLSError: TLSError([0x7180] 'SSL - Verification of the message MAC failed')
ssl_tls.c:6800: => free
The same errors occur when all cipher suites are enabled, so am pretty sure the problem isn't the cipher.
Suggestions for diagnosis appreciated. Thanks.
Though a similar question got answered in the Nordic DevZone it may be also the answer for this question.
For openssl, "010102030405060708090a0b0c0d0e0f" results in a 16 bytes secret.
About
b'010102030405060708090a0b0c0d0e0f'
I'm not that sure. From other SO questions, I think it's a 32 bytes secret.
If the peers don't share the same secret, the handshake fails. Some implementations will simple timeout the handshake, other may report a MAC validation error, because a mismatching secret creates different association keys, and with that, the MAC validation of the handshake 'Finish' fails.
Either use "30 31 30 31 30 32 30 33 30 34 30 35 30 36 30 37 30 38 30 39 30 61 30 62 30 63 30 64 30 65 30 66" (remove the spaces!) for openssl, or use b'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f' for python.
Hope, that works.
I'm trying to build a TCP-proxy script that sends and receives data, i managed to get it to listen but it doesn't seem to be connecting properly...my code looks right to me and after checking python docs(i'm trying to run it in python 2.7 and 3.6) i get this timeout message:
Output:
anon#kali:~/Desktop/python scripts$ sudo python TCP\ proxy.py 127.0.0.1 21 ftp.target.ca 21 True
[*] Listening on 127.0.0.1:21d
[==>] Received incoming connection from 127.0.0.1:44806d
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 754, in run
self.__target(*self.__args, **self.__kwargs)
File "TCP proxy.py", line 60, in proxy_handler
remote_socket.connect((remote_host,remote_port))
File "/usr/lib/python2.7/socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
error: [Errno 110] Connection timed out
i looked into the file "/usr/lib/python2.7/socket.py" but couldn't really understand what i was looking for as it seemed right when i compared it to python docs and my script
my code:
# import the modules
import sys
import socket
import threading
#define the server
def server_loop(local_host,local_port,remote_host,remote_port,receive_first):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
server.bind((local_host, local_port))
server.listen(5)
print ("[*] Listening on %s:%sd" % (local_host, local_port))
except:
print("[!!] Failed to listen on %s:%sd" % (local_host,local_port))
print ("[!!] Check for others listening sockets or correct permissions")
sys.exit(0)
while True:
client_socket, addr = server.accept()
#print out the local connection information
print ("[==>] Received incoming connection from %s:%sd" % (addr[0],addr[1]))
#start a thread to talk to the remote host
proxy_thread = threading.Thread(target=proxy_handler,args=(client_socket,remote_host,remote_port,receive_first))
proxy_thread.start()
else:
print ("something went wrong")
def main():
#no fancy command-line parasing here
if len(sys.argv[1:]) !=5:
print ("Usage: ./TCP proxy.py [localhost] [localport] [remotehost] [remoteport] [receive_first]")
print("Example: ./TCP proxy.py 127.0.0.1 9000 10.12.132.1 9000 True")
#set up local listening parameters
local_host = sys.argv[1]
local_port = int(sys.argv[2])
#set up remote target
remote_host = sys.argv[3]
remote_port = int(sys.argv[4])
#this tells proxy to connect and receive data before sending to remote host
receive_first = sys.argv[5]
if "True" in receive_first:
receive_first = True
else:
receive_first = False
#now spin up our listening socket
server_loop(local_host,local_port,remote_host,remote_port,receive_first)
def proxy_handler(client_socket, remote_host, remote_port, receive_first):
#connect to the remote host
remote_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
remote_socket.connect((remote_host,remote_port))
#receive data from the remote end if necessary
if receive_first:
remote_buffer = receive_from(remote_socket)
hexdump(remote_buffer)
#send it to the repsonse handler
remote_buffer = respsonse_handler(remote_buffer)
#if data is able to be sent to local client, send it
if len(remote_buffer):
print ("[<==] Sending %d bytes to localhost." % len(remote_buffer))
client_socket.send(remote_buffer)
#now loop and read from local,sent to remote,send to local,rinse/wash/repeat
while True:
#read from local host
local_buffer = receive_from(client_socket)
if len(local_buffer):
print ("[==>] Received %d bytes from localhost." % len(local_buffer))
#send it to request handler
local_buffer = request_handler(local_buffer)
#send data to remote host
remote_socket.send(local_buffer)
print ("[==>] Sent to remote.")
#receive back response
remote_buffer = receive_from(remote_socket)
if len(remote_buffer):
print ("[<==] Received %d bytes from remote." % len(remote_buffer))
hexdump(remote_buffer)
#send response to handler
remote_buffer = response_handler(remote_buffer)
#send response to local socket
client_socket.send(remote_buffer)
print ("[<==] Sent to localhost.")
#if no data left on either side, close connection
if not len(local_buffer) or not len(remote_buffer):
client_socket.close()
remote_socket.close()
print ("[*] No more data, closing connections.")
break
#this is a pretty hex dumping function taken from the comments of http://code.activestate.com/recipes/142812-hex-dumper/
def hexdump(src, length=16):
result = []
digits = 4 if isinstance(src,unicode) else 2
for i in xrange(0,len(src), length):
s = src[i:i+length]
hexa = b' '.join(["%0*X" % (digits, ord(x)) for x in s])
text = b' '.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s])
result.append( b"%04X %-*s %s" % (i, length*(digits + 1), hexa, text) )
print (b'/n'.join(result))
def receive_from(connection):
buffer = ""
#set a 2 second timeout; depending on your target this may need to be adjusted
connection.settimeout(2)
try:
#keep reading the buffer until no more data is there or it times out
while True:
data = connection.recv(4096)
if not data:
break
buffer += data
except:
pass
return buffer
#modify any requested destined for the remote host
def request_handler(buffer):
#perform packet modifications
return buffer
#modify any responses destined for the local host
def response_handler(buffer):
#perform packet modifications
return buffer
main()
i have tried different ftp servers/sites,etc but get the same result, where am i going wrong with my code? any input or direction would be greatly appreciated.
okay so turns out my script is good just the ftp servers i was running weren't haha
this is the final output:
anon#kali:~/Desktop/python scripts$ sudo python TCP\ proxy.py 127.0.0.1 21 ftp.uconn.edu 21 True
[*] Listening on 127.0.0.1:21d
[==>] Received incoming connection from 127.0.0.1:51532d
0000 32 32 30 20 50 72 6F 46 54 50 44 20 31 2E 32 2E 2 2 0 P r o F T P D 1 . 2 ./n0010 31 30 20 53 65 72 76 65 72 20 28 66 74 70 2E 75 1 0 S e r v e r ( f t p . u/n0020 63 6F 6E 6E 2E 65 64 75 29 20 5B 31 33 37 2E 39 c o n n . e d u ) [ 1 3 7 . 9/n0030 39 2E 32 36 2E 35 32 5D 0D 0A 9 . 2 6 . 5 2 ] . .
[<==] Sending 58 bytes to localhost.
[==>] Received 353 bytes from localhost.
[==>] Sent to remote.
[<==] Received 337 bytes from remote.
I try to do simple async http client with asyncore:
This code works fine and output is (fast enought):
www.gmail.com : recv http code: 301
www.yandex.ru : recv http code: 200
www.python.org : recv http code: 200
www.google.ru : recv http code: 200
www.gravatar.com : recv http code: 302
www.com.com : recv http code: 302
www.yahoo.com : recv http code: 302
www.bom.com : recv http code: 301
But than i uncomment line with not exist host:
#c = AsyncHTTP('http://www.no-such-host.ru') #!this line breaks execution!
The execution breaks, code hangs for some time, output part of data and hangs with no last data output:
connection error: [Errno -5] No address associated with hostname
www.gmail.com : recv http code: 301
www.yandex.ru : recv http code: 200
www.yahoo.com : recv http code: 302
www.com.com : recv http code: 302
www.bom.com : recv http code: 301
www.gravatar.com : recv http code: 302
...
some hosts are lost here and long delay at start.
Why this happen and how to fix this?
# coding=utf-8
import asyncore
import string, socket
import StringIO
import mimetools, urlparse
class AsyncHTTP(asyncore.dispatcher):
# HTTP requestor
def __init__(self, uri):
asyncore.dispatcher.__init__(self)
self.uri = uri
# turn the uri into a valid request
scheme, host, path, params, query, fragment = urlparse.urlparse(uri)
assert scheme == "http", "only supports HTTP requests"
try:
host, port = string.split(host, ":", 1)
port = int(port)
except (TypeError, ValueError):
port = 80 # default port
if not path:
path = "/"
if params:
path = path + ";" + params
if query:
path = path + "?" + query
self.request = "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n" % (path, host)
self.host = host
self.port = port
self.status = None
self.header = None
self.http_code = None
self.data = ""
# get things going!
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
#self.connect((host, port))
#return
try:
self.connect((host, port))
except Exception,e:
self.close()
self.handle_connect_expt(e)
def handle_connect(self):
self.send(self.request)
def handle_expt(self):
print "handle_expt error!"
self.close()
def handle_error(self):
print "handle_error error!"
self.close()
def handle_connect_expt(self,expt):
print "connection error:",expt
def handle_code(self):
print self.host," : ","recv http code: ",self.http_code
def handle_read(self):
data = self.recv(2048)
#print data
if not self.header:
self.data = self.data + data
try:
i = string.index(self.data, "\r\n\r\n")
except ValueError:
return # continue
else:
# parse header
fp = StringIO.StringIO(self.data[:i+4])
# status line is "HTTP/version status message"
status = fp.readline()
self.status = string.split(status, " ", 2)
self.http_code = self.status[1]
self.handle_code()
# followed by a rfc822-style message header
self.header = mimetools.Message(fp)
# followed by a newline, and the payload (if any)
data = self.data[i+4:]
self.data = ""
#header recived
#self.close()
def handle_close(self):
self.close()
c = AsyncHTTP('http://www.python.org')
c = AsyncHTTP('http://www.yandex.ru')
c = AsyncHTTP('http://www.google.ru')
c = AsyncHTTP('http://www.gmail.com')
c = AsyncHTTP('http://www.gravatar.com')
c = AsyncHTTP('http://www.yahoo.com')
c = AsyncHTTP('http://www.com.com')
c = AsyncHTTP('http://www.bom.com')
#c = AsyncHTTP('http://www.no-such-host.ru') #!this line breaks execution!
asyncore.loop()
ps: My system ubuntu 11.10 + python 2.7.2
You invoke a blocking name-resolution when you do self.connect((host, port)). Combined with your local DNS configuration, this is why your program has a long delay at startup.
An alternative to asyncore and figuring out how to do non-blocking name resolution yourself, you might think about using Twisted. Twisted's TCP connection setup API (mainly reactor.connectTCP or one of the APIs built on top of it) does not block. So a naive use of it will remain properly asynchronous.