Python raw socket receive issue - python

I am using the following python script for raw socket packet transfer. Packet transfer is fine, but I am not able to print the incoming packet from the other end.
from socket import socket, AF_PACKET, SOCK_RAW
s = socket(AF_PACKET, SOCK_RAW)
s.bind(("eth0", 0))
src_addr = "\x54\xbe\xf7\x40\xf5\x82"
dst_addr = "\xff\xff\xff\xff\xff\xff"
payload = ("[("*30)+"Hello"+("]"*30)
checksum = "\x1a\x2b\x3c\x4d"
data = payload+checksum
s.send(dst_addr+src_addr+data)
#for receive function
response=s.recv(4096)
print response
s.close()

There is a third argument to the socket function: protocol. If not given, it's defaulting to 0. For AF_PACKET / SOCK_RAW, the protocol argument specifies what kind of packets you're interested in receiving. The values are documented in the packet(7) man page: http://man7.org/linux/man-pages/man7/packet.7.html
I don't think the values are actually defined anywhere in the core python2 modules. Some of them can be found in scapy (http://www.secdev.org/projects/scapy/), or you can just hunt up the linux header file where they are defined (/usr/include/linux/if_ether.h).
So, to fix this, change your code to:
from socket import socket, AF_PACKET, SOCK_RAW, htons
ETH_P_ALL = 3
ETH_P_IP = 0x800 # Alternatively using this will receive the next IP packet
s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
...
Other comments on your code:
As written, the packet you're sending is unlikely to be comprehensible by anyone. You've got a dst and src MAC address, but then you're not providing an EtherType. Instead the first "[(" will be seen as the EtherType. That probably won't make sense to any receiver of the packet so it will just be discarded.
Also, you should understand that with a raw socket, you're going to receive the next packet of the type you've specified in the protocol. That isn't necessarily (and in fact probably won't be) a response to the packet you just sent.

Thanks everyone now I am able receive the packet with the following the script. But still I am facing issue with printing multiple response packets(While doing in loop).
from socket import socket, AF_PACKET, SOCK_RAW, htons
from struct import *
import select
import time
ETH_P_ALL = 3
ETH_P_IP = 0x800
s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
s.bind(("eth0", 0))
src_addr = "\x54\xbe\xf7\x40\xf7\x82"
dst_addr = "\xff\xff\xff\xff\xff\xff"
l = "\x00\x21"
ethertype = "\x08\x01"
a ="\x00\x10\x00\x10\x00\x10"
b = "\x00\x11\x00\x11\x00\x11"
payload = ethertype + l + a + b
for i in range(5):
time.sleep(5)
s.send(dst_addr+src_addr+ payload)
message=s.recv(4096)
print message

Related

Socket Fragmented Received Data

I'm trying to create some kind of client monitor, like a terminal, to receive data from a serial device over ethernet. I'm trying to use a socket with python, but the problem comes when I create the connection. I'm supposed to receive only one message from the server, and I get the whole message but split into two packets, like this:
Message expected:
b'-- VOID MESSAGE--'
Message received:
b'-- VOID'
b' MESSAGE--'
I don't know if is this a problem of buffer size, decoding or any other function
import socket
TCP_IP = '192.168.#.#'
TCP_PORT = ###
BUFFER_SIZE = 1024
data1=' '
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
while(1):
data = s.recv(BUFFER_SIZE)
print(data.decode('ASCII'))
s.close()
I've already tried with some codecs options like UTF-8, UTF-16 and ASCII but I still get the same result.
This function helped me to solve the issue.
while(1):
cadena += s.recv(1)
if (((cadena)[i])=='\n'):
print(cadena.decode('ASCII'))
cadena=b''
i=-1
i+=1
As it already was said - that's how sockets works.
Sent data could be splitted to chunks. So if you want to be sure, that you've received whole message that was sent you need to implement some kind of protocol, the part of which will be contain length of your message. For example:
First four bytes (integer) represents length of the message
Other bytes - content of the message
In such case algorithm to send a message will be look like:
Count length of the message
Write to socket integer (4 bytes) with message length
Write to socket content of the message
And reading algorithm:
Read bytes from socket and write read data to accumulator-buffer
Read first four bytes from buffer as integer - it will be message length
Check if buffer length is greater or equal "{message length} + 4"
If it's then read required amount of bytes and that will message that was sent.
Drop first "{message length} + 4" bytes from buffer
Repeat from second point
If it's not enough bytes to read message content repeat from first point.
One solution is to use UDP instead of TCP if you can live with the limitations:
There is a size limit, the data must fit into one packet
UDP is "unreliable".
A TCP connection transfer one single stream of bytes. OTOH UDP transfers individual datagrams (messages). If the sender sends N datagrams, the recipient shall receive the same N datagrams. Maybe out of order, maybe some will get lost, but each datagram is independent of all others.
Regarding the limitations, these are not so simple questions. There is plenty of information on these topics, just search.
The max size depends on factors like IPv4 or IPv6, fragmentation etc. and there is a best case and a worst case. Typically you can assume that one ethernet frame (for all headers + payload) is absolutely without problems.
The "unreliability" does not mean the quality of transfer is terrible. The network should work on "best effort" basis. It means there are no ACKs, timeouts and retransmits. You can live without it or you can add simple ACKs to your protocol.
You can use this example.
Server code: (read from client)
#!/usr/bin/python3
from socket import socket, gethostname
s = socket()
host = gethostname()
port = 3399
s.bind((host, port))
s.listen(5)
while True:
print("Listening for connections...")
connection, addr = s.accept()
try:
buffer = connection.recv(1024)
response = ''
while buffer:
response += buffer.decode('ASCII')
buffer = connection.recv(1024)
print(response)
connection.close()
except KeyboardInterrupt:
if connection:
connection.close()
break
Client code: (send message)
#!/usr/bin/python3
from socket import socket, gethostname
s = socket()
host = gethostname()
port = 3399
s.connect((host, port))
print("Sending text..")
s.sendall(b'-- VOID MESSAGE--')
print("Done sending..")
s.close()

Can socket receive infinite data stream python?

While trying to attempt to go for python based socket, I have 2 questions which I am not able to resolve. Kindly help me. Here is my sample socket code:
import socket
import threading
import chardet
bind_ip = '0.0.0.0'
bind_port = 9999
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip, bind_port))
server.listen(1) # max backlog of connections
print (('Listening on {}:{}').format(bind_ip, bind_port))
def handle_client_connection(client_socket):
request = client_socket.recv(4096 )
result = chardet.detect(request)
print(result)
print (request.decode(result['encoding']))
client_socket.send('ACK!'.encode(result['encoding']))
client_socket.close()
while True:
client_sock, address = server.accept()
print (('Accepted connection from {}:{}').format(address[0], address[1]))
client_handler = threading.Thread(
target=handle_client_connection,
args=(client_sock,) # without comma you'd get a... TypeError: handle_client_connection() argument after * must be a sequence, not _socketobject
)
client_handler.start()
The above one is server and the below is client:
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 9999))
client.send(str('test data').encode("utf-16"))
response = client.recv(4096)
print(response.decode("utf-16"))
Now the questions:
1) What is the meaning of the number in this statement: client.recv(4096)? What is 4096, is it bit or byte of kilobyte for data receiving?
2) Can I receive infinite data stream through the socket? Meaning, as this statement client.recv(4096), whatever is the menaing of 4096, may be byte, then the socket will receive the 4096 bytes of data only. I do not have a control on the size of data received through the socket, hence, can I generalize it to accept any size of data through socket?
Please help me get the answers to above queries. I tried the python documentation for socket but didn't found much. I guess I miss something. Please help me get through it.
According to documentation
"If a message is too long to fit in the supplied buffer, excess bytes may be discarded depending on the type of socket the message is received from."
found here
"https://linux.die.net/man/2/recv"
which was from python 3.6 docs
"he maximum amount of data to be received at once is specified by bufsize. See the Unix manual page recv(2)"
found here
"https://docs.python.org/3.6/library/socket.html"
so it is a bytes object and it may actually truncate the message depending on the protocol. So message integrity is handled by the next layer up. So presumably you would loose part of a UDP packet, and you would get either a retry or an additional packet for TCP if the message was too large to fit in the buffer.

"[Errno 1] Operation not permitted" when creating socket

I am trying to use the program DigiKey have made for their Amazon Dash Button hack to monitor for when the button is pressed and then send a HTTP GET to IFTTT. I am using a Raspberry Pi to run this. Source:
import socket
import struct
import binascii
import time
import json
import urllib2
# Use your own IFTTT key
ifttt_key = 'example_key'
# Set these up at https://ifttt.com/maker
ifttt_url_button = 'https://maker.ifttt.com/trigger/button_pressed/with/key/' + ifttt_key
# Replace this MAC addresses and nickname with your own
macs = {
'xxxxxxxxxxxx' : 'vanish'
}
# Trigger a IFTTT URL. Body includes JSON with timestamp values.
def trigger_url(url):
data = '{ "value1" : "' + time.strftime("%Y-%m-%d") + '", "value2" : "' + time.strftime("%H:%M") + '" }'
req = urllib2.Request(url, data, {'Content-Type': 'application/json'})
f = urllib2.urlopen(req)
response = f.read()
f.close()
return response
def button_pressed():
print 'triggering button event, response:' + trigger_url(ifttt_url_button)
rawSocket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.htons(0x0003))
while True:
packet = rawSocket.recvfrom(2048)
ethernet_header = packet[0][0:14]
ethernet_detailed = struct.unpack("!6s6s2s", ethernet_header)
# skip non-ARP packets
ethertype = ethernet_detailed[2]
if ethertype != '\x08\x06':
continue
# read out data
arp_header = packet[0][14:42]
arp_detailed = struct.unpack("2s2s1s1s2s6s4s6s4s", arp_header)
source_mac = binascii.hexlify(arp_detailed[5])
source_ip = socket.inet_ntoa(arp_detailed[6])
dest_ip = socket.inet_ntoa(arp_detailed[8])
if source_mac in macs:
#print "ARP from " + macs[source_mac] + " with IP " + source_ip
if macs[source_mac] == 'vanish':
button_pressed()
else:
print "Unknown MAC " + source_mac + " from IP " + source_ip
The error I receive is:
Traceback (most recent call last):
File "/home/pi/Desktop/dash_btn.py", line 30, in <module>
rawSocket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.htons(0x0003))
File "/usr/lib/python2.7/socket.py", line 187, in __init__
_sock = _realsocket(family, type, proto)
error: [Errno 1] Operation not permitted
I have tried running it in the terminal with sudo , but it hasn't changed anything. Help would be appreciated.
Since you wish to receive and parse ARP packets (which are on a link layer, OSI layer 2, below IP level you receive with AF_INET), you'll have to use the low-level packet interface, AF_PACKET.
From man packet (for AF_PACKET sockets):
The socket_type is either SOCK_RAW for raw packets including the link-level header or SOCK_DGRAM for cooked packets with
the link-level header removed. The link-level header information is available in a common format in a sockaddr_ll structure. protocol is the IEEE 802.3 protocol number in network byte order. See the <linux/if_ether.h> include file for a list of allowed protocols. When protocol is set to htons(ETH_P_ALL), then all protocols are received. All incoming
packets of that protocol type will be passed to the packet socket before they are passed to the protocols implemented in the kernel.
So, for sniffing ARP packets, you must use SOCK_RAW socket type. However, to use it, from man 7 raw:
Only processes with an effective user ID of 0 or the CAP_NET_RAW capability are allowed to open raw sockets.
therefore, you'll have to run your program with sudo.
For socket protocol (third parameter) you might choose 0x0003 as you already have, which means ETH_P_ALL, receiving all packages, or probably better, ETH_P_ARP which has a value of 0x0806 (see your /usr/include/linux/if_ether.h) to receive only ARP packages.
All taken together, this looks like this:
rawSocket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0806))
while True:
packet = rawSocket.recvfrom(2048)
# no need to filter-out ARP
# less load on user program

when i made a 3 handshake with ubuntu in VMware return package R

#!/usr/bin/python
from scapy.all import *
def findWeb():
a = sr1(IP(dst="8.8.8.8")/UDP()/DNS(qd=DNSQR(qname="www.google.com")),verbose=0)
return a[DNSRR].rdata
def sendPacket(dst,src):
ip = IP(dst = dst)
SYN = TCP(sport=1500, dport=80, flags='S')
SYNACK = sr1(ip/SYN)
my_ack = SYNACK.seq + 1
ACK = TCP(sport=1050, dport=80, flags='A', ack=my_ack)
send(ip/ACK)
payload = "stuff"
PUSH = TCP(sport=1050, dport=80, flags='PA', seq=11, ack=my_ack)
send(ip/PUSH/payload)
http = sr1(ip/TCP()/'GET /index.html HTTP/1.0 \n\n',verbose=0)
print http.show()
src = '10.0.0.24'
dst = findWeb()
sendPacket(dst,src)
I'm trying to do HTTP packets with SCAPY
I am using UBUNTU on VMwaer
The problem is that every time I send messages I have RESET
How do we fix it?
Thanks
sniff package image
Few things I notice wrong.
1. You have your sequence number set statically (seq=11) which is wrong. Sequence numbers are always randomly generated and they must be used as per RFC793. So the sequence should be = SYNACK[TCP].ack
You set your source port as 1500 during SYN packet, but then you use it as 1050 (typo?)
You don't need extra payload/PUSH.
Also, have a look at these threads:
How to create HTTP GET request Scapy?
Python-Scapy or the like-How can I create an HTTP GET request at the packet level

Sending and Receiving arrays via Sockets

Is it possible to send an array through UDP Sockets using Python? I am using Python 2.5 and trying to send a simple array but it's not working. It can send the array successfully but when I try to print it with an item of the array the program crashes. I'm not sure what the error is as I take the precaution of converting the data into an array but it's not working. Hope I explained the problem as clearly as possible. I would appreciate the help!
# Client program
from socket import *
import numpy
from array import*
# Set the socket parameters
host = "localhost"
port = 21567
buf = 4096
addr = (host,port)
# Create socket
UDPSock = socket(AF_INET,SOCK_DGRAM)
def_msg = "===Enter message to send to server===";
print "\n",def_msg
a = array('i',[1,3,2])
# Send messages
while (1):
data = raw_input('yes or now')
if data!= "yes":
break
else:
if(UDPSock.sendto(a,addr)):
print "Sending message"
# Close socket
UDPSock.close()
# Server program
from socket import *
# Set the socket parameters
host = "localhost"
port = 21567
buf = 4096
addr = (host,port)
# Create socket and bind to address
UDPSock = socket(AF_INET,SOCK_DGRAM)
UDPSock.bind(addr)
# Receive messages
while 1:
data,addr = UDPSock.recvfrom(buf)
L = eval(data)
if not data:
print "Client has exited!"
break
else:
print "\nReceived message '", L[1],"'"
# Close socket
UDPSock.close()
eval is doing something completely different than what you think.
To send data over network, you need to serialize it into an array of bytes, then deserialize it back. In Python, serialization of most objects can be done via pickle module:
if (UDPSock.sendto( pickle.dumps(a), addr)):
Deserialization:
data,addr = UDPSock.recvfrom(buf)
L = pickle.loads(data)
print repr(L) # prints array('i', [1, 3, 2])
I would personally use tostring and fromstring since the built-in serialization methods are many times faster and pickle may not support NaN, Inf and other undefined values.
You're trying to send a python object through a socket, it is normal that it doesn't work, you can't send objects in a socket, objects are not data, they are the representation of some data in a given programming language. You need to "translate" your object to data and re-create the object from the data on the other socket's side. One way to do this would be with the pickle module.
On the client side, you "pickle" the object:
data = pickle.dumps(my_array)
And on the server side, you "unpickle" the received data:
my_array = pickle.loads(received_data)
You could try to pickle the array. Pickle is a python library to en- and decode python objects. It is able to do much more, but it is definitely sufficient to fulfill your task:
on the sender side you pickle the object to a string:
pickled_string = pickle.dumps(a)
on the receiver side you unpickle the object:
a = pickle.loads(received_string)
# a is now your sent array
It has been a while since this question was asked, but I thought it's worth sharing the jsonsocket library. It makes it really easy to send strings, lists and dictionaries over sockets. It can handle big amounts of data efficiently. And you don't need to do any manual serialization/deserialization. Under the hood, it serializes the data as JSON strings on the client, and deserializes it on the server.
If you don't need UDP specifically, try zmqObjectExchanger (https://github.com/ZdenekM/zmq_object_exchanger). It wraps pickle and zmq to transfer python objects over TCP.

Categories