I am using the code below to try to send an MMS message with python-messaging https://github.com/pmarti/python-messaging/blob/master/doc/tutorial/mms.rst Although the connection seems to go smoothly I get the following response from the mmsc:
PROXY RESPONSE HTTP/1.0 200 OK
content-type: application/vnd.wap.mms-message
content-length: 59
Connection: close
Date: Sat, 05 Jan 2019 16:36:44 GMT
Server: Mavenir Web Application Server
���1234�����,�Failed to handle HTTP request in Mm1Server
Does, anyone have an idea on what the problem might be and how I can fix it? Here is my code:
from messaging.mms.message import MMSMessage, MMSMessagePage
mms = MMSMessage()
mms.headers['To'] = '+212XXXXXXX/TYPE=PLMN'
mms.headers['Message-Type'] = 'm-send-req'
mms.headers['Subject'] = 'Test python-messaging.mms'
slide1 = MMSMessagePage()
slide1.add_image('/home/richard/screensaver/TolleConscQte.jpg')
slide1.add_text('This first slide, is a step towards enlightenment.')
slide2 = MMSMessagePage()
slide2.set_duration(4500)
slide2.add_image('/home/richard/screensaver/TollePastALL.jpg', 1500)
slide2.add_text('This second slide is a second step towards enlightenment.', 500, 3500)
mms.add_page(slide1)
mms.add_page(slide2)
payload = mms.encode()
## sending the MMS
from cStringIO import StringIO
import socket
gw_host, gw_port = "10.188.239.143", 80 #ting
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((gw_host, gw_port))
s.send("POST %s HTTP/1.0\r\n" % "http://wholesale.mmsmvno.com/mms/wapenc")
s.send("Content-Type: application/vnd.wap.mms-message\r\n")
s.send("Content-Length: %d\r\n\r\n" % len(payload))
s.sendall(payload)
buf = StringIO()
while True:
data = s.recv(4096)
if not data:
break
buf.write(data)
s.close()
data = buf.getvalue()
buf.close()
print "PROXY RESPONSE", data
Related
I'm trying to code a python script through which I want to send packets from one host (desktop ubuntu) to a server (Ubuntu server) using multiple source addresses. I decided that would be best to use raw sockets and define my own TCP and IP header. I succeed to send the SYN packet and also get a response with the SYN-ACK packet but then my host doesn't respond with the ACK packet but with the RST packet. This is the first problem with I met in my solution. After the beginning of a three-way handshake I would like to send an HTTP GET keep-alive request. Does anyone know how to do it? Or does anyone know a better solution or library to use?
def send_raw_socket():
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
version_ihl_type_of_service = b'\x45\x00'
total_length = b'\x00\x3c'
Indentification = b'\xab\xcd'
flags_fragment_offset = b'\x00\x00'
TTL_protocol = b'\x40\x06'
Dest_add = b'\x0a\x0a'
Dest_add2 = b'\x1e\x03'
Src_add = b'\x0a\x0a'
src_add2 =b'\x0a\x0a'
Header_Checksum = my_ip_header_checksum(version_ihl_type_of_service, total_length, Indentification, flags_fragment_offset, TTL_protocol, Src_add,src_add2, Dest_add, Dest_add2)
IP_protocol = b'\x00\x06'
TCP_header_lenght = b'\x00\x14'
src_port = (int(src_port.hex(), 16)+49607).to_bytes(2, byteorder='big')
dest_port = b'\x1f\x95' # Source Port | Destination Port
seq_n1 = b'\x00\x00'
seq_n2 = b'\x00\x00' # Sequence Number
ack_n1 = b'\x00\x00'
ack_n2 = b'\x00\x00' # Acknowledgement Number
do_res = b'\x50\x02'
flags_win_s = b'\x71\x10' # Data Offset, Reserved, Flags | Window Size
checksum= tcp_header_checksum(IP_protocol, Src_add, src_add2, Dest_add, Dest_add2, TCP_header_lenght, src_port, dest_port, seq_n1, seq_n2, ack_n1, ack_n2, do_res, flags_win_s)
u_pinter= b'\x00\x00' # Checksum | Urgent Pointer
packet = version_ihl_type_of_service+total_length+Indentification+flags_fragment_offset+TTL_protocol+Header_Checksum+Src_add+src_add2+Dest_add+Dest_add2+src_port+dest_port+seq_n1+seq_n2+ack_n1+ack_n2+do_res+flags_win_s+checksum+u_pinter
s.sendto(packet, ('10.10.30.3',8085))
Wireshark three-way handshake
I am new to python and my networking logics are at the beginner level. I have an HTTP server running in a VM and when I curl it from a different terminal on the same machine, I get the expected response. I am looking for a functionality where I can get the same response on my mobile device when I type the ip and port in the browser. My mobile device is connected to the same WiFi. Here's the server code:
import socket
MAX_PACKET = 32768
def recv_all(sock):
r'''Receive everything from `sock`, until timeout occurs, meaning sender
is exhausted, return result as string.'''
# dirty hack to simplify this stuff - you should really use zero timeout,
# deal with async socket and implement finite automata to handle incoming data
prev_timeout = sock.gettimeout()
try:
sock.settimeout(0.01)
rdata = []
while True:
try:
rdata.append(sock.recv(MAX_PACKET))
except socket.timeout:
return ''.join(rdata)
# unreachable
finally:
sock.settimeout(prev_timeout)
def normalize_line_endings(s):
r'''Convert string containing various line endings like \n, \r or \r\n,
to uniform \n.'''
return ''.join((line + '\n') for line in s.splitlines())
def run():
r'''Main loop'''
# Create TCP socket listening on 10000 port for all connections,
# with connection queue of length 1
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, \
socket.IPPROTO_TCP)
server_sock.bind(('10.0.2.15',80))
server_sock.listen(1)
while True:
# accept connection
client_sock, client_addr = server_sock.accept()
# headers and body are divided with \n\n (or \r\n\r\n - that's why we
# normalize endings). In real application usage, you should handle
# all variations of line endings not to screw request body
request = normalize_line_endings(recv_all(client_sock)) # hack again
request_head, request_body = request.split('\n\n', 1)
# first line is request headline, and others are headers
request_head = request_head.splitlines()
request_headline = request_head[0]
# headers have their name up to first ': '. In real world uses, they
# could duplicate, and dict drops duplicates by default, so
# be aware of this.
request_headers = dict(x.split(': ', 1) for x in request_head[1:])
# headline has form of "POST /can/i/haz/requests HTTP/1.0"
request_method, request_uri, request_proto = request_headline.split(' ', 3)
response_body = [
'<html><body><h1>Hello, world!</h1>',
'<p>This page is in location %(request_uri)r, was requested ' % locals(),
'using %(request_method)r, and with %(request_proto)r.</p>' % locals(),
'<p>Request body is %(request_body)r</p>' % locals(),
'<p>Actual set of headers received:</p>',
'<ul>',
]
for request_header_name, request_header_value in request_headers.iteritems():
response_body.append('<li><b>%r</b> == %r</li>' % (request_header_name, \
request_header_value))
response_body.append('</ul></body></html>')
response_body_raw = ''.join(response_body)
# Clearly state that connection will be closed after this response,
# and specify length of response body
response_headers = {
'Content-Type': 'text/html; encoding=utf8',
'Content-Length': len(response_body_raw),
'Connection': 'close',
}
response_headers_raw = ''.join('%s: %s\n' % (k, v) for k, v in \
response_headers.iteritems())
# Reply as HTTP/1.1 server, saying "HTTP OK" (code 200).
response_proto = 'HTTP/1.1'
response_status = '200'
response_status_text = 'OK' # this can be random
# sending all this stuff
client_sock.send('%s %s %s' % (response_proto, response_status, \
response_status_text))
client_sock.send(response_headers_raw)
client_sock.send('\n') # to separate headers from body
client_sock.send(response_body_raw)
# and closing connection, as we stated before
client_sock.close()
run()
Here's the response when I run curl from a different terminal on the same VM.
I want to ping it from my mobile device connected to the same WiFi. Thank you!
In Python, when I run this code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import socket
s=socket.socket()
s.connect(('www.sina.com.cn',80))
s.send(b'GET /HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')
buffer=[]
while True:
d=s.recv(1024)
if d:
buffer.append(d)
else:
break
data=b''.join(buffer)
s.close()
header,html = data.split(b'\r\n\r\n',1)
print(header.decode('utf-8'))
with open('sina_test.html','wb') as f:
f.write(html)
I get this error:
line 19, in (header,html,h) = data.split(b'\r\n\r\n',1)
ValueError: need more than 1 value to unpack
What does that error mean?
The second argument to split method limits how many items the method will return
header,html = data.split(b'\r\n\r\n',1)
Here you are trying to unpack more than 1 even though you specified that split should only return 1 item
There's a SPACE before the HTTP
# wrong
s.send(b'GET /HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')
# correct
s.send(b'GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')
The wrong usage maybe send you this information:
print(data)
<HTML>\n<HEAD>\n<TITLE>Not Found on Accelerator</TITLE>\n</HEAD>\n\n<BODY BGCOLOR="white" FGCOLOR="black">\n<H1>Not Found on Accelerator</H1>\n<HR>\n\n<FONT FACE="Helvetica,Arial"><B>\nDescription: Your request on the specified host was not found.\nCheck the location and try again.\n</B></FONT>\n<HR>\n</BODY>\n
The right information is just like this:
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 23 Jan 2018 03:28:38 GMT
Content-Type: text/html
Content-Length: 605221
Connection: close
Last-Modified: Tue, 23 Jan 2018 03:27:02 GMT
Vary: Accept-Encoding
Expires: Tue, 23 Jan 2018 03:29:37 GMT
Cache-Control: max-age=60
X-Powered-By: shci_v1.03
Age: 1
Via: http/1.1 ctc.jiangsu.ha2ts4.82 (ApacheTrafficServer/6.2.1 [cHs f ])
X-Cache: HIT.82
X-Via-CDN: f=edge,s=ctc.jiangsu.ha2ts4.83.nb.sinaedge.com,c=58.213.91.6;f=Edge,s=ctc.jiangsu.ha2ts4.82,c=61.155.142.83
X-Via-Edge: 1516678118627065bd53afa8e9b3d553f23b9
That's why ValueError occurs.
This error means that your string (data) does not contain the regex you are trying to split accordingly and therefore - data.split(b'\r\n\r\n',1) == data which cannot be assigned to header and html.
I am trying to measure the responses back from DNS servers. Making a sniffer for a typical DNS response that is less than 512 bytes is no big deal. My issue is receiving large 3000+ byte responses - in some cases 5000+ bytes. I haven't been able to get a socket working that can receive that data reliably. Is there a way with Python sockets to receive from a specific source address?
Here is what I have so far:
import socket
import struct
def craft_dns(Qdns):
iden = struct.pack('!H', randint(0, 65535))
QR_thru_RD = chr(int('00000001', 2)) # '\x01'
RA_thru_RCode = chr(int('00100000', 2)) # '\x00'
Qcount = '\x00\x01' # question count is 1
ANcount = '\x00\x00'
NScount = '\x00\x00'
ARcount = '\x00\x01' # additional resource count is 1
pad = '\x00' #
Rtype_ANY = '\x00\xff' # Request ANY record
PROtype = '\x00\x01' # Protocol IN || '\x00\xff' # Protocol ANY
DNSsec_do = chr(int('10000000', 2)) # flips DNSsec bit to enable
edns0 = '\x00\x00\x29\x10\x00\x00\x00\x00\x00\x00\x00' # DNSsec disabled
domain = Qdns.split('.')
quest = ''
for x in domain:
quest += struct.pack('!B', len(x)) + x
packet = (iden+QR_thru_RD+RA_thru_RCode+Qcount+ANcount+NScount+ARcount+
quest+pad+Rtype_ANY+PROtype+edns0) # remove pad if asking <root>
return packet
def craft_ip(target, resolv):
ip_ver_len = int('01000101', 2) # IPvers: 4, 0100 | IP_hdr len: 5, 0101 = 69
ipvers = 4
ip_tos = 0
ip_len = 0 # socket will put in the right length
iden = randint(0, 65535)
ip_frag = 0 # off
ttl = 255
ip_proto = socket.IPPROTO_UDP # dns, brah
chksm = 0 # socket will do the checksum
s_addr = socket.inet_aton(target)
d_addr = socket.inet_aton(resolv)
ip_hdr = struct.pack('!BBHHHBBH4s4s', ip_ver_len, ip_tos, ip_len, iden,
ip_frag, ttl, ip_proto, chksm, s_addr, d_addr)
return ip_hdr
def craft_udp(sport, dest_port, packet):
#sport = randint(0, 65535) # not recommended to do a random port generation
udp_len = 8 + len(packet) # calculate length of UDP frame in bytes.
chksm = 0 # socket fills in
udp_hdr = struct.pack('!HHHH', sport, dest_port, udp_len, chksm)
return udp_hdr
def get_len(resolv, domain):
target = "10.0.0.3"
d_port = 53
s_port = 5353
ip_hdr = craft_ip(target, resolv)
dns_payload = craft_dns(domain) # '\x00' for root
udp_hdr = craft_udp(s_port, d_port, dns_payload)
packet = ip_hdr + udp_hdr + dns_payload
buf = bytearray("-" * 60000)
recvSock = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0800))
recvSock.settimeout(1)
sendSock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
sendSock.settimeout(1)
sendSock.connect((resolv, d_port))
sendSock.send(packet)
msglen = 0
while True:
try:
pkt = recvSock.recvfrom(65535)
msglen += len(pkt[0])
print repr(pkt[0])
except socket.timeout as e:
break
sendSock.close()
recvSock.close()
return msglen
result = get_len('75.75.75.75', 'isc.org')
print result
For some reason doing
pkt = sendSock.recvfrom(65535)
Recieves nothing at all. Since I'm using SOCK_RAW the above code is less than ideal, but it works - sort of. If the socket is extremely noisy (like on a WLAN), I could end up receiving well beyond the DNS packets, because I have no way to know when to stop receiving packets when receiving a multipacket DNS answer. For a quiet network, like a lab VM, it works.
Is there a better way to use a receiving socket in this case?
Obviously from the code, I'm not that strong with Python sockets.
I have to send with SOCK_RAW because I am constructing the packet in a raw format. If I use SOCK_DGRAM the custom packet will be malformed when sending to a DNS resolver.
The only way I could see is to use the raw sockets receiver (recvSock.recv or recvfrom) and unpack each packet, look if the source and dest address match within what is supplied in get_len(), then look to see if the fragment bit is flipped. Then record the byte length of each packet with len(). I'd rather not do that. It just seems there is a better way.
Ok I was stupid and didn't look at the protocol for the receiving socket. Socket gets kind of flaky when you try to receive packets on a IPPROTO_RAW protocol, so we do need two sockets. By changing to IPPROTO_UDP and then binding it, the socket was able to follow the complete DNS response over multiple requests. I got rid of the try/catch and the while loop, as it was no longer necessary and I'm able to pull the response length with this block:
recvSock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
recvSock.settimeout(.3)
recvSock.bind((target, s_port))
sendSock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
#sendSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sendSock.settimeout(.3)
sendSock.bind((target, s_port))
sendSock.connect((resolv, d_port))
sendSock.send(packet)
pkt = recvSock.recvfrom(65535)
msglen = len(pkt[0])
Now the method will return the exact bytes received from a DNS query. I'll leave this up in case anyone else needs to do something similar :)
I'm doing a test about sending me the fake http response by using scapy,
however whireshark shows the fake response is "TCP ACKed unseen segment",
here is my code:
pkgs = sniff(iface="eth0",filter="src host 192.168.1.153 and dst host 121.42.144.212 and tcp and port 80", lfilter = lambda x: x.haslayer(Raw), count=1)
for pkg in pkgs:
d_port = pkg[IP].sport #if i set d_port like 5555 , it will work, but if d_port= pkg[IP].sport, the packet is wrong
ether = Ether(dst='00:0c:29:2c:0e:4e', src='8c:be:be:23:97:80')
ip = IP(src='121.42.144.212', dst='192.168.1.153', flags="DF")
tcp = TCP(flags="PA", sport=80, dport=d_port, seq=1,ack=87)
res_data = "HTTP/1.1 200 OK\r\nDate: Thu, 02 Jul 2015 04:19:50 GMT\r\nServer: Apache/2.4.10 (Win32) OpenSSL/0.9.8zb PHP/5.3.29\r\nX-Powered-By: PHP/5.3.29\r\nContent-Length: 4\r\nContent-Type: text/html\r\n\r\njoke"
res = ether/ip/tcp/res_data
#ls(res)
sendp(res)
and wireshirk shows "Transmission Control Protocol, Src Port: http (80), Dst Port: 37938 (37938), Seq: 511606687, Ack: 1126945895, Len: 188", the seq and ack is bigger than I set.
and is this a bug or something is wrong in my code?
I'sorry, I found out that this may be wireshark's problem.