I am having some problems using raw IPv6 sockets in python. I connect via:
if self._socket != None:
# Close out old socket first
self._socket.close()
self._socket = socket.socket(socket.AF_INET6, socket.SOCK_RAW)
self._socket.bind((self._interface,0))
self._socket.sendall(data)
where self._interface is my local address; specifically "fe80::fa1e:dfff:fed6:221d". When trying this, I get the following error:
File "raw.py", line 164, in connect
self._socket.bind((self._interface,0))
File "<string>", line 1, in bind
socket.error: [Errno 49] Can't assign requested address
If I use my ipv6 localhost address for self._interface ("::1") I can actually bind the address, but can not send anything:
self._socket.sendall(data)
File "<string>", line 1, in sendall
socket.error: [Errno 39] Destination address required
Why would a raw socket need a destination address? Has anyone worked with raw IPv6 sockets in python, and can help me understand why this is happening?
Although this is an old question, i thought of adding an answer that works and helps any one who stumbles upon it latter.
The key problems are:
Raw sockets are not bound and connected to other sockets. Also sendto is the correct api to use.
Moreover, 4 tuple structure for destination address is required for ipv6 packets as opposed to two tuple ones for ipv4.
Lastly, the stack (at least on Linux mint 15) is more strict on ipv6 packets. If you try sending an empty icmpv4 echo request, python allows it and sends a meaning less packet on wire. Where as in case of ipv6, it simply gives error of 'invalid argument' when you try sending an empty packet. Hence a valid request is also required in case of ipv6. Following example does that all for ipv6 and sends a valid ping echo request to loop back address.
import socket
def main(dest_name):
addrs = socket.getaddrinfo(dest_name, 0, socket.AF_INET6, 0, socket.SOL_IP)
print addrs
dest = addrs[0]
# A minimal ICMP6-echo message (thanks to abarnert)
data = '\x80\0\0\0\0\0\0\0'
icmp = socket.getprotobyname('ipv6-icmp')
#print icmp
send_socket = socket.socket(socket.AF_INET6, socket.SOCK_RAW, icmp)
print "sent to " + str(dest[4])
send_socket.sendto(data, dest[4])
send_socket.close()
if __name__ == '__main__':
main('::1')
I don't understand your combination of bind and sendall. In my understanding, bind is for server sockets and sendall requires a connection. Did you mean connect instead of bind?
Anyway, the IPv6 equivalent of INADDR_ANY is, according to the man page, IN6ADDR_ANY_INIT. Python does not define a constant for it, but this is the same as '::' (all zero).
This worked for me (as root):
>>> import socket
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_RAW)
>>> s.bind(('::', 0))
EDIT:
Oops, I first did not saw that you actually managed to bind the socket to an address. However your second problem is obvious: You must first connect to some address before you can send data. Or use sendto with an address. This is not different from IPv4.
This code provides a raw socket with L2 access. Unfortunately OSX does not support the socket.PF_PACKET...
soc = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) #create the raw-socket
soc.bind(("lo0", 0))
soc.send(packet)
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 trying to create a simple server to client based chat program and the issue is that when I try to execute c.sendto(data,client) this error appears saying that Client is an int but it's a tuple containing the port number and the address. I'm I supposed to convert the tuple to bytes so I can send the message to the clients?
Server Script
import socket
clients = []
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("127.0.0.1",7999))
s.listen()
print("Waiting for connection")
c, addr = s.accept()
while True:
data , addr = c.recvfrom(1024)
print(data)
if addr not in clients:
clients.append(addr)
print(clients[0])
if data:
for client in clients:
print(client)
c.sendto(data,client)
s.close()
Client Script
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
addr = ("127.0.0.1",7999)
s.connect(addr)
while True:
string = input(">>")
s.send(string.encode("utf-8"))
data =s.recv(1024)
s.close()
Server Output
The problem is that you're using sendto() with a connection-mode socket. I think you want c.send(data) instead.
Details:
The Python docs for sendto say "The socket should not be connected to a remote socket, since the destination socket is specified by address." Also the man page for sendto says "If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) socket, the arguments dest_addr and addrlen are ignored (and the error EISCONN may be returned when they are not NULL and 0)." I somewhat suspect that this is happening and Python is misreporting the error in a confusing way.
The sockets interface and networking in general can be pretty confusing but basically sendto() is reserved for SOCK_DGRAM which is UDP/IP type internet traffic, which you can think of as sending letters or postcards to a recipient. Each one goes out with a recipient address on it and there's no guarantee on order of receipt. On the other hand, connection-mode sockets like SOCK_STREAM use TCP/IP which is a bit more like a phone call in that you make a connection for a certain duration and and each thing you send is delivered in order at each end.
Since your code seems to be designed for communication over a connection I think you just want c.send(data) and not sendto.
You must first convert the string that contains the IP address into a byte or a string of bytes and then start communicating.
According to the code below, your error will be resolved.
Make sure your code is working correctly overall.
string = '192.168.1.102'
new_string = bytearray(string,"ascii")
ip_receiver = new_string
s.sendto(text.encode(), (ip_receiver, 5252))
Here is my code:
ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, 3)
ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30)
ins.bind((interface_name, 3))
while True:
fmt = "B"*7+"I"*21
pkt, sa_ll = self.ins.recvfrom(65535)
x = struct.unpack(fmt, ins.getsockopt(socket.IPPROTO_TCP, socket.TCP_INFO, 92))
print "===>",x
print "HEX Packet",hexlify(pkt)
process_ipframe(sa_ll[2],hexlify(pkt))
Getting socket.error: [Errno 92] Protocol not available error. Or is there any better way to get the TCP(Need only ESTAB connctions) states for the connections.
Ok, my requirement is to get the established connections. But I was sniffing traffic on the interface for other purpose. So, I though I could get TCP states from raw sockets. But I found /proc/net/tcp: there is st field, from that I can get ESTABLISHED connections. So, I should read /proc/net/tcp continuously to get ESTAB for a specific time in different thread.
So, the answer is /proc/net/tcp. Check this question. or may I should use netfilter
I am following this example,
#!/usr/bin/python # This is server.py file
import socket # Import socket module
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
port = 12345 # Reserve a port for your service.
s.bind((host, port)) # Bind to the port
s.listen(5) # Now wait for client connection.
while True:
c, addr = s.accept() # Establish connection with client.
print 'Got connection from', addr
c.send('Thank you for connecting')
c.close() # Close the connection
and I am getting this error despite good network:
>>> s.bind((host, port))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Applications/anaconda/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
socket.gaierror: [Errno 8] nodename nor servname provided, or not known
How can I fix this?
Let's take a look at the docs:
socket.gethostname()
Return a string containing the hostname of the
machine where the Python interpreter is currently executing.
If you want to know the current machine’s IP address, you may want to
use gethostbyname(gethostname()). This operation assumes that there is
a valid address-to-host mapping for the host, and the assumption does
not always hold.
Note: gethostname() doesn’t always return the fully qualified domain
name; use getfqdn() (see above).
I guess this is what's happening: bind is trying to establish IP address for the host, but it fails. Run host = socket.gethostbyname(socket.gethostname()) and instead of a valid IP address you'll most probably see the same error as when calling bind.
You say the returned hostname is valid, but you have to make sure it's recognised by the DNS responder. Does the resolution work when doing, for example, ping {hostname} from the command line?
Possible solutions would be:
Fix your local DNS resolution.
Use host = socket.getfqdn() (in case you were not getting the fully qualified name which then couldn't be resolved properly). Even if it works I think you should try and fix the local resolution.
Use empty host (host = ''), which on bind would mean "listen on all available interfaces". (This is the first example in the docs.)
I try to implement 3-way-hadnshake with a raw socket in Python and using Scapy.
The code is:
s=socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.IPPROTO_TCP)
ss=StreamSocket(s)
iph=IPheader()
syn = TCP(sport=TCP_SOURCE_PORT,dport=TCP_DESTINATION_PORT, flags="S")
synack = ss.sr1(iph/syn)
myack = iph/TCP(dport=synack[TCP].sport, sport=synack[TCP].dport, seq=synack[TCP].ack, ack=synack[TCP].seq+1, flags="A")
ss.send(myack)
IPheader() method return a scapy IP header.
When running the script i get this error:
ERROR: --- Error in child 3057
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/scapy/sendrecv.py", line 89, in sndrcv
pks.send(p)
File "/usr/lib/python2.7/dist-packages/scapy/supersocket.py", line 34, in send
return self.outs.send(sx)
error: [Errno 6] No such device or address
I see a couple of possible problems with your code:
before invoking StreamSocket() you need to establish a connection with a regular socket. So you need to make a connection, something like s.connect(("10.1.1.1",9000)) before the line ss=StreamSocket(s). Further information can be found here
You may need to correct base socket type. I would suggest something like s=socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP). For further information check this
The device is not responding to your SYN packet because a RAW socket does not do that. You have to send the SYN-ACK manually. Also, Wireshark and TCP show sequence numbers as RELATIVE. In order to show the ACTUAL number you must turn this option off. Thirdly, you can set the sequence number manually or randomize it using
TCP(sport = port1, dport = port2, flags="A", seq = random.getrandbits(32), ack = MY_ACK)
or
TCP(sport = port1, dport = port2, flags="A", seq = 01395, ack = MY_ACK)