Is it possible to connect to a different subnet or domain by python socket programming?
I want to make a script for sharing files with friends,, but currently I only know how to
connect within one LAN.
in LAN, you should broadcast packets to discover each other.
and every peer should listen the port to receive broadcast.
It is discovery protocol, you can implement it by UDP socket.
Once two peer decide to communicate, they should create a TCP socket. Then, they can send data via TCP.
Or you can use HTTP, XML-RPC etc. to transfer data(not broadcast, TCP is not support broadcast).
#udp broadcast
import socket, time
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
while True:
data = 'test'.encode()
s.sendto(data, ('255.255.255.255', 1080))
time.sleep(1)
#udp receive broadcast
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', 1080))
while True:
print(s.recv(1024))
Related
I try to send messages in localhost to broadcast address, but it does not work. When I use socket.INADDR_BROADCAST, I get [Errno 11001] getaddrinfo failed.
import socket
client_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_server.bind(("127.0.0.1", 12345))
client_server.connect((f"{socket.INADDR_BROADCAST}", 12345))
client_server.sendto("New user is connected".encode("utf-8"), (f"{socket.INADDR_BROADCAST}", 12345))
You are creating a TCP (SOCK_STREAM) socket. TCP has no notion of broadcasting. A TCP client socket cannot connect() to a broadcast IP, and a TCP server socket cannot listen() on a broadcast IP. That just makes no sense to do. The only way to broadcast a message in TCP is for the server to keep track of each client connected to it and then send the message to each client one at a time.
A UDP (SOCK_DGRAM) socket, on the other hand, can sendto() a message to a broadcast IP (if you enable the socket's SO_BROADCAST option beforehand), and it can recvfrom() a message that was sent to a broadcast IP belonging to the adapter that the socket is bound to.
Just note that bind()'ing a broadcasting UDP socket to 127.0.0.1 means that only UDP receivers also bound to 127.0.0.1 will be able to receive the broadcasts. You won't be able to broadcast over the network.
import socket
client_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#client_server.bind(("127.0.0.1", 12345))
client_server.setsockopt(client_server.SOL_SOCKET, client_server.SO_BROADCAST, 1)
client_server.sendto("New user is connected".encode("utf-8"), (f"{socket.INADDR_BROADCAST}", 12345))
I have a UDP communication between a server and client on localhost
according to this code:
https://pymotw.com/2/socket/udp.html
Echo Server:
import socket
import sys
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('127.0.0.1', 12321)
sock.bind(server_address)
while True:
data, address = sock.recvfrom(4096)
if data:
sent = sock.sendto(data, address)
echo Client
import socket
import sys
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address = ('127.0.0.1', 12321)
message = 'This is the message. It will be repeated.'
try:
for i in range 4:
sent = sock.sendto(message, server_address)
data, server = sock.recvfrom(4096)
finally:
sock.close()
now let's say I got some MITM attack, and a specific packet doesn't arrive at the server, and the client is still waiting for a response from the server,
I get a deadlock.
how can I overcome this? is there some timeout parameter for UDP socket?
Yes, there is a timeout for UDP sockets. See socket.settimeout() in https://docs.python.org/2/library/socket.html and read up on non-blocking sockets in general.
Note that UDP packets can be dropped, duplicated, and/or re-ordered, even if there is no man-in-the-middle attacker. This is because UDP is (by design) an unreliable datagram protocol.
If you need a reliable protocol use TCP (or QUIC).
If you need assurance that no man-in-the-middle can modify or (optionally) observe the data, use TLS (or QUIC).
I'm building a python server that basically has a bunch of ports listening for connections. when a connection is made, the port spits out a message, closes the connection and , resets (ie waits for the next connection).
desired function:
create TCP socket for each port in portlist (this is dynamically populated via arguments)
listen for connection
when a connection made, send message, and disconnect
continue to listen
I have a feeling that my answer may ly in multi threading, but I'm not sure...My code so far:
for port in portlist:
ds = ("0.0.0.0", port)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(ds)
server.listen(1)
while 1:
connection, address = server.accept()
message="message\n"
connection.send(message)
connection.close()
There is single-threaded approach (on the listening side anyway - actually handling the connections may still require multiple threads).
You should open all of your sockets up-front, and put them in a list.
Then, you should select on all of them, which will return when any one of them is ready to be accepted on.
Something like this (totally untested):
servers = []
for port in portlist:
ds = ("0.0.0.0", port)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(ds)
server.listen(1)
servers.append(server)
while True:
# Wait for any of the listening servers to get a client
# connection attempt
readable,_,_ = select.select(servers, [], [])
ready_server = readable[0]
connection, address = ready_server.accept()
# Might want to spawn thread here to handle connection,
# if it is long-lived
Can anyone tell me the most basic approach to generate UDP, TCP, and IP Packets with Python?
As suggested by jokeysmurf, you can craft packets with scapy
If you you want to send/receive regular, i.e. non-custom, packets then you should use socket or socketserver:
http://docs.python.org/library/socket.html#module-socket
http://docs.python.org/library/socketserver.html#module-SocketServer
For example, to send a TCP HTTP GET request to Google's port 80 use:
import socket
HOST = 'google.com' # The remote host
PORT = 80 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send('GET / HTTP/1.1\r\nHost: google.com\r\n\r\n')
data = s.recv(1024)
s.close()
print 'Received', repr(data)
To send UDP instead of TCP change SOCK_STREAM to SOCK_DGRAM.
You can do interactive packet manipulation with scapy.
This article is going to get you started on gluing together an IP packet.
Construction of a tcp packet is as easy as:
packet = IP(src="10.0.0.10")
This following is a straightforward IPv4 UDP broadcast, followed by listening on all interfaces.
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
sock.bind(("", 1337))
sock.sendto("hello world", ("255.255.255.255", 1337))
while True:
data, addr = sock.recvfrom(0x100)
print "received from {0}: {1!r}".format(addr, data)
I want to adjust this to send and receive both IPv4 and IPv6.
I've poked around and read as much as I can and believe the following is roughly the route I need to take:
Create an IPv6 socket.
Add the socket to a link or site local multicast group.
Send the UDP packets to the multicast address for the group in use.
Further info I have is that I may need to bind to several interfaces, and tell the socket using setsockopt() that it should also receive multicast packets. Lastly getaddrinfo() can be used across the board to gracefully "drop back" to IPv4 where IPv6 isn't available.
I have much of this implemented, but stumble primarily on the multicasting parts. A complete code example in Python, or vivid description of the constants and addresses needed are preferred.
Here's a link to python mcast demo, does both IPv4 and IPv6.
I'm currently asking a question over here that involves getting the multicast address of a received message, but the source code answers your question!
To listen:
# Initialise socket for IPv6 datagrams
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
# Allows address to be reused
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Binds to all interfaces on the given port
sock.bind(('', 8080))
# Allow messages from this socket to loop back for development
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, True)
# Construct message for joining multicast group
mreq = struct.pack("16s15s".encode('utf-8'), socket.inet_pton(socket.AF_INET6, "ff02::abcd:1"), (chr(0) * 16).encode('utf-8'))
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
data, addr = sock.recvfrom(1024)
and to send:
# Create ipv6 datagram socket
sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
# Allow own messages to be sent back (for local testing)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_LOOP, True)
sock.sendto("hello world".encode('utf-8'), ("ff02::abcd:1", 8080))
This is for python3.6, with python 2.7 I don't think the encodes are necessary. Also in the struct.pack line, I've seen variations of "16s15s" such as "4s", but I don't know what it is and what I have worked for me!