I am trying to open a raw socket with Python under linux.
My simple code:
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
s.bind((HOST, 5454))
And I got this error:
[ERROR] Protocol not supported
By the way, I am using python 2.7.3 under linux 12.04, and I used root to run the code.
Does anyone have a clue?
Update: The solution given by dstromberg is correct. If you want the whole packet, then use his solution. However, there is another combination:
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
that also works.
In this case, you will receive a whole TCP packet with IP and TCP headers on it.
If your use dstromberg's solution, you will also see the ethernet header. So it depends on how 'raw' you want your packet to be.
Try socket.AF_PACKET instead of socket.AF_INET.
This runs without error as root:
#!/usr/local/cpython-3.3/bin/python
import socket as socket_mod
#s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
socket = socket_mod.socket(socket_mod.AF_PACKET, socket_mod.SOCK_RAW, socket_mod.IPPROTO_IP)
#socket.bind(('localhost', 5454))
socket.bind(('lo', 5454))
Try socket.AF_UNIX, it can solve your problem, good luck.
Related
Ok guys, I can't understand this code:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
What does:
socket.AF_INET
socket.SOCK_STREAM
do?
I really read everything abount them, but I can't understand what dows they do, could you please explain me, them in simple words?Thanks for read, have a great day!
TL;DR
socket.AF_INET = The type of socket address
socket.SOCK_STREAM = The type of socket
Explanation
Whenever you provide socket.AF_INET to your server you instruct it to listen to an IPv4 address, and to your client to connect to an IPv4 address. This will work. Same for IPv6. However mixing them up doesn't.
That would be the same me waiting for you to talk to me on StackOverflow while you send me messages by email. We are not looking at the same spot, so we won't be able to communicate.
Same for socket.SOCK_STREAM (and the other values). The difference lies in the fact that this tells python's socket how we are going to communicate. socket.SOCK_STREAM will be TCP, while socket.SOCK_DGRAM will be UDP.
Let's come back to our "real world" example and let's imagine we agreed on communicating by email. I could expect either one email from you (explaining me everything you have to tell) or several (with a part of what you have to say in each email). That's the same as TCP vs UDP.
References
Well, I guess you have read both:
python's socket module
python's socket How to
Potentially:
SO: What is Address Family?
Wikipedia: IPv4
Also, I guess:
Difference Between Socket Types
(and the references therein)
Wikipedia: Network socket - Types
Super long explanation but mostly testing
So. If after all that you don't understand. Let's try:
# server.py
import socket
s = socket.socket()
s.bind(('localhost', 5050))
s.listen(5)
while True:
(clientsocket, address) = s.accept()
print 'client connected'
And:
# client.py
import socket
s = socket.socket(socket.AF_INET)
s.connect(('127.0.0.1', 5050))
print "Yeah! I'm connected :)"
So far, everything as in the how to.
We launch our server:
$ python server.py
And then we launch our client:
$ python client.py
Yeah! I'm connected :)
Everything works fine. That's good.
Now, lets change our client:
# client.py
import socket
s = socket.socket(socket.AF_INET6)
s.connect(('127.0.0.1', 5050))
print "Yeah! I'm connected :)"
And relaunch our new client:
$ python client.py
Traceback (most recent call last):
File "client.py", line 4, in <module>
s.connect(('127.0.0.1', 5050))
File "/.../lib/python2.7/socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 65] No route to host
Aie! Everything breaks!
But what happens? 127.0.0.1:5050 is an IPv4 address, hence the socket module tells us it's not happy about what we are doing! Indeed, we said our connection will be using an IPv6 address but we are providing it with an IPv4 address.
Okay... But if I use the same address but in IPv6, will it work? Let's try by changing our client (you could check out this SO answer for the equivalent of 127.0.0.1 for IPv6):
# client.py
import socket
s = socket.socket(socket.AF_INET6)
s.connect(('::1', 5050))
print "Yeah! I'm connected :)"
and our server:
# server.py
import socket
s = socket.socket(socket.AF_INET6)
s.bind(('::1', 5050))
s.listen(5)
while True:
(clientsocket, address) = s.accept()
print 'client connected'
We relaunch our server and our client:
$ python client.py
Yeah! I'm connected :)
Success!
The same procedure could be used to understand/test the socket.SOCK_STREAM parameter (but I think my answer is already long enough).
Hope this helped :).
socket.STREAM is the kind of socket you want. In this case, you are looking to stream bytes to and from the host you want to connect to, rather than just issue a one-time call. This means that the socket will listen for bytes until it receives an empty byte b'', at which point it will terminate the connection (because the stream is complete).
I would imagine you aren't too worried about the type of socket, so low-level understanding here isn't paramount, nor could I give you a particularly satisfactory answer to that, either.
socket.AF_INET is the AddressFamily, ipv4 or ipv6. This tells sockets what kind of address to expect. You will most likely use ipv4, so (host, port) tuple will work just fine.
AF_INET is well described in there. It is basically the method you are using for sending data over to the other socket. SOCK_STREAM basically describes that you are sending using TCP and essentially describes rules for the endpoint to which you are sending and recieving data (IP adress and port number).
But since you seem confused over these terms I'd suggest just just think of them as specifications on how you are going to transmit data between your two socket endpoints.
I'm currently having a lot of trouble while writing a raw socket.
While my implementation is pretty big by now, i think solving the problem for the following code, would also solve it for my whole implementation:
from scapy.all import *
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
src_port = 12345 # any random port > 1024 i guess ...
dst_port = 80 # should be tcp, as http runs over it in the end
dst_addr = socket.gethostbyname("www.google.de")
# ensuring that kernel will not create its own ip header
sock.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, True)
# create a packet to send using scapy
packet = IP(dst = dst_addr)/TCP(dport = dst_port)
sock.sendto(bytes(packet), (dst_addr, 80))
I get the following error :
OS error: [Errno 22] Invalid argument
which is raised by:
sock.sendto(bytes(packet), (dst_addr, 80))
Does someone have a clue, why this is not working?
-- EDIT --
I'm working on MacOSX.
I already noticed this question: Raw sockets and sendto in python
However, I'm hoping that someone has an answer anyways, as the old question lacks a good answer and is also around 4 years old.
As context to my question, I am a computing student getting started with Python for the first time. Before this, I've worked mostly with Java and I am most comfortable with Java conventions and practices right now.
Background
An assignment for socket programming asks that we send strings between a server and client locally on the machine. We are provided sample (Python 2) code that instantiates a server and client. Outside of the context of the assignment, I wanted to create a version of this code that also runs in Python 3, but I was having problems getting the client to work the same in Python 3.
Changing server and client
Originally, the server required little changes and I was able to get it working. My code for the server is as follows:
#!/usr/bin/python3
import socket
HOST=''
PORT=5870
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((HOST, PORT))
sock.listen(1)
conn, addr = sock.accept()
print('Connected by ', addr)
conn.sendto("Welcome to the server!", (HOST, PORT))
while True:
data = conn.recv(1024)
if not data: break
conn.sendall(data)
conn.close()
I'm not able to convert the client side to code that runs and functions within Python 3. I've tried digging deeper into the issue, but other online resources are not helpful for me (or at least, at my experience level). My server code is as follows.
#!/usr/bin/python3
import socket
HOST='127.0.0.1'
PORT=5870
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
data = sock.recv(1024)
print('Server sent', data)
sock.sendto("Hello world".encode(), (HOST, PORT))
data = sock.recv(1024)
print("Server sent", data)
sock.sendto("This is the second message".encode(), (HOST, PORT))
data = sock.recv(1024)
print('Server sent ', data)
sock.close()
The actual problem
Originally, this code for both the server and client used sendall() instead of sendto(), but I changed it after getting a TypeError in the client and reading this question. I'm still not exactly sure why this works or why I have to do this (although I would appreciate an explanation).
Now, when I run the client code, I'll get the same TypeError on the server even when I'm using sendto(), but I'm not sure how to resolve this problem in Python 3. The stacktrace I receive for the server as follows (I get a broken pipe on the client):
$ python3 mail_server.py
Connected by ('127.0.0.1', 41866)
Traceback (most recent call last):
File "mail_server.py", line 14, in <module>
conn.sendto("Welcome to the server!", (HOST, PORT))
TypeError: a bytes-like object is required, not 'str'
What am I doing wrong and how am I able to get this working in Python 3? Background context as to why this is would be especially helpful as I think part of my problem is that I'm not seeing why this change is necessary to begin with. Thanks!
Don't use sendto() on a stream socket. Once a socket is connected (and with stream sockets you can't do any data transfer until after connecting), you can't specify the destination, it's always sent to the remote address/port to which it's connected.
So use send() or sendall():
socket.sendall("Hello world".encode());
I have a mobile router that can be configured by using different Python script. What I need to do is read all the packets arriving to the router in a concrete UDP port to copy this information in a .txt file afterwards.
Anyone can give me some tips about how can I do this using Python? How can I detect every time a packet arrives in to the router?
Thank you.
Here's a quick example of how to bind to a UDP port and do some action whenever a datagram is received:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', 9800))
try:
while True:
result, who = s.recvfrom(256)
print result, who
finally:
s.close()
I am trying to read the UDP packages in python, which were sent from an FPGA. I see the packages in wireshark, and they look allright. Python, however does not receive anything when I use this simple script:
import socket
import sys
HOST, PORT = "192.168.1.1", 21844
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.connect((HOST,PORT))
received = sock.recv(1024)
You don't connect with a UDP server (I assume the Python code is the server), you bind.