I wanted to write simple udp port scanner on python and I faced some problems.
First of all am I understand right that there are 3 options:
send UDP - get nothing -> port is filtered|opened
send UDP - get icmp port unreachable -> port is closed
send UDP - get UDP - port is opened
I create raw socket, create ip header and udp header. In udp header write the dest port and add some data.
Then I send it to server and with select wait for a reply. But nothing neither on opened port nor on closed. Only timeout.
And is it possible to send just dummy data but not correct packet of the next level ?
[Update 1]
Added more data to send in udp packet. Now I get udp packet back from (194.226.244.126, 53) but my host send back icmp type 3 to 194.226.244.126 before I could read any recieved data. But still no response from 8.8.8.8
[Update 2]
Found that 8.8.8.8 reply only on correct dns packets. But still can't read udp packet with raw socket.
import socket
import time
import select
import sys
from packets_headers import iphdr, udphdr
from get_ip import Getip
timeout = 3
host = "8.8.8.8"
port = 53
my_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW)
udp_header = udphdr(b"00000000000000000", port, 4242)
udp_packet = udp_header.assemble()
g = Getip()
ip_packet_header = iphdr(socket.IPPROTO_UDP, g.get_lan_ip(), host)
ip_packet_header.data = udp_packet
ip_packet = ip_packet_header.assemble()
my_socket.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
full_packet = ip_packet
while full_packet:
sent = my_socket.sendto(full_packet, (host, port))
full_packet = full_packet[sent:]
ready = select.select([my_socket], [], [], timeout)
if ready[0] == []: # Timeout
print("Timeout")
sys.exit()
rec_packet, addr = my_socket.recvfrom(1024)
print(rec_packet, addr)
Also packets_header.py
import socket
import struct
import random
class iphdr(object):
"""
This represents an IP packet header.
#assemble packages the packet
#disassemble disassembles the packet
"""
def __init__(self, proto=socket.IPPROTO_ICMP, src="0.0.0.0", dst=None):
self.version = 4
self.hlen = 5
self.tos = 0
self.length = 20
self.id = random.randint(2 ** 10, 2 ** 16)
self.frag = 0
self.ttl = 255
self.proto = proto
self.cksum = 0
self.src = src
self.saddr = socket.inet_aton(src)
self.dst = dst or "0.0.0.0"
self.daddr = socket.inet_aton(self.dst)
self.data = ""
def assemble(self):
header = struct.pack('BBHHHBB',
(self.version & 0x0f) << 4 | (self.hlen & 0x0f),
self.tos, self.length + len(self.data),
socket.htons(self.id), self.frag,
self.ttl, self.proto)
self._raw = header + b"\x00\x00" + self.saddr + self.daddr + self.data
return self._raw
#classmethod
def disassemble(self, data):
self._raw = data
ip = iphdr()
pkt = struct.unpack('!BBHHHBBH', data[:12])
ip.version = (pkt[0] >> 4 & 0x0f)
ip.hlen = (pkt[0] & 0x0f)
ip.tos, ip.length, ip.id, ip.frag, ip.ttl, ip.proto, ip.cksum = pkt[1:]
ip.saddr = data[12:16]
ip.daddr = data[16:20]
ip.src = socket.inet_ntoa(ip.saddr)
ip.dst = socket.inet_ntoa(ip.daddr)
return ip
def __repr__(self):
return "IP (tos %s, ttl %s, id %s, frag %s, proto %s, length %s) " \
"%s -> %s" % \
(self.tos, self.ttl, self.id, self.frag, self.proto,
self.length, self.src, self.dst)
class udphdr(object):
def __init__(self, data="", dport=4242, sport=4242):
self.dport = dport
self.sport = sport
self.cksum = 0
self.length = 0
self.data = data
def assemble(self):
self.length = len(self.data) + 8
part1 = struct.pack("!HHH", self.sport, self.dport, self.length)
cksum = self.checksum(self.data)
cksum = struct.pack("!H", cksum)
self._raw = part1 + cksum + self.data
return self._raw
#classmethod
def checksum(self, data):
# XXX implement proper checksum
cksum = 0
return cksum
def disassemble(self, data):
self._raw = data
udp = udphdr()
pkt = struct.unpack("!HHHH", data)
udp.src_port, udp.dst_port, udp.length, udp.cksum = pkt
return udp
Related
I am creating a very simple rdt 2.2 socket program that transfers an image file dictated as "Cat.bmp" from client to server. Once the client reads the first line of data from the bmp file, it sends it to the server, and then the server will continue to repeat reading this same line in an infinite loop. I have no idea why this won't allow the client to send new data. Any suggestions on how to fix this would be very appreciated.
Client.py
import binascii
import struct
import sys
import hashlib
import base64
import time
from asyncio.tasks import sleep
def rdtSend(currentSequence , currentAck , data):
values = (currentACK, currentSequence, data)
UDPData = struct.Struct('I I 8s')
packedData = UDPData.pack(*values)
checksumVal = hashlib.md5(packedData).hexdigest().encode('utf-8')
sendPacket = makepacket(currentACK, currentSequence, data, checksumVal)
UDPSend(sendPacket)
def makepacket(currentACK, currentSequence, data, checksumVal):
values = (currentACK, currentSequence, data, checksumVal)
packetData = struct.Struct('I I 8s 32s')
packet = packetData.pack(*values)
return packet
def UDPSend(sendPacket):
senderSocket.sendto(sendPacket, (IP, Port))
def dataError(receivePacket):
checksum = makeChecksum(receivePacket[0], receivePacket[1], receivePacket[2])
# Compare calculated chechsum with checksum value in packet
if receivePacket[3] == checksum:
print('CheckSums is OK')
return False
else:
print('CheckSums Do Not Match')
return True
def makeChecksum(ACK, SEQ, DATA):
values = (ACK, SEQ, DATA)
packer = struct.Struct('I I 8s')
packedData = packer.pack(*values)
checksum = hashlib.md5(packedData).hexdigest().encode('utf-8')
return checksum
def isACK(receivePacket, ACKVal):
if (receivePacket[0] == ACKVal):
return True
else:
return False
IP = "127.0.0.1"
#Local Port for client and server
Port = 20001
#buffer to receive information from client
bufferSize = 1024
unpacker = struct.Struct('I I 8s 32s')
senderSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
senderSocket.connect((IP , Port))
print("UDP IP:", IP)
print("UDP port:", Port)
filename = 'Cat.bmp'
file = open(filename , 'rb')
# current data item being processed
data = file.read(bufferSize)
currentSequence = 0
currentACK = 0
while (data):
rdtSend(currentSequence, currentACK , data)
packet, addr = senderSocket.recvfrom(bufferSize)
print(packet)
print("Received from: ", addr)
receivePacket = unpacker.unpack(packet)
if(dataError(receivePacket) == False and isACK(receivePacket , currentACK) == True):
currentACK = currentACK + 1
currentSequence = (currentSequence + 1) % 2
data = file.read(bufferSize)
print("sending more data")
else:
print("Resending packet")
file.close()
senderSocket.close
Server.py
import socket
import binascii
import struct
import sys
import hashlib
import base64
import time
from asyncio.tasks import sleep
def rdtSend(currentSequence , currentAck , data):
values = (currentACK, currentSequence, data)
UDPData = struct.Struct('I I 8s')
packedData = UDPData.pack(*values)
checksumVal = hashlib.md5(packedData).hexdigest().encode('utf-8')
#This is where it gets the UDP packet
sendPacket = makepacket(currentACK, currentSequence, data, checksumVal)
UDPSend(sendPacket)
def makepacket(currentACK, currentSequence, data, checksumVal):
values = (currentACK, currentSequence, data, checksumVal)
packetData = struct.Struct('I I 8s 32s')
packet = packetData.pack(*values)
return packet
def UDPSend(sendPacket):
receiverSocket.sendto(sendPacket, (IP, Port))
def makeChecksum(ACK, SEQ, DATA):
values = (ACK, SEQ, DATA)
packer = struct.Struct('I I 8s')
packedData = packer.pack(*values)
checksum = hashlib.md5(packedData).hexdigest().encode('utf-8')
return checksum
#Function that checks the packet for corruption
def dataError(receivePacket):
# Calculate new checksum of the [ ACK, SEQ, DATA ]
checksum = makeChecksum(receivePacket[0], receivePacket[1], receivePacket[2])
# Compare calculated chechsum with checksum value in packet
if receivePacket[3] == checksum:
print('CheckSums is OK')
return False
else:
print('CheckSums Do Not Match')
return True
#IP Address for local communications
IP = "127.0.0.1"
#Local Port for client and server
Port = 20001
#buffer to receive information from client
bufferSize = 1024
# Integer, Integer, 8 letter char array, 32 letter char array
unpacker = struct.Struct('I I 8s 32s')
# Create the actual UDP socket for the server
receiverSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Bind the socket to the local IP address and port
receiverSocket.bind((IP, Port))
currentACK = 0
currentSequence = 0
dataFile = open('receive.bmp' , 'wb')
print("Listening")
packet, addr = receiverSocket.recvfrom(bufferSize)
receivedPacket = unpacker.unpack(packet)
#Where the previous functions are used to send the packets back to the client
while receivedPacket[2]:
print("Received from:", addr)
print("Data Received:" , receivedPacket[2])
#This compares checksums to see if there are errors
if not dataError(receivedPacket):
dataFile.write(receivedPacket[2])
# Built checksum [ACK, SEQ, DATA]
ACK = receivedPacket[0]
SEQ = receivedPacket[1]
DATA = b''
print('Packeting')
rdtSend(currentSequence , currentACK , DATA)
print('Sent')
currentACK = currentACK + 1
currentSequence = (currentSequence + 1) % 2
packet, addr = receiverSocket.recvfrom(bufferSize)
receivedPacket = unpacker.unpack(packet)
else:
print('Packet error')
checksumVal = makeChecksum(packet[0] + 1, (packet[1] + 1) % 2, b'')
packet = makepacket(packet[0] + 1, (packet[1] + 1) % 2, b'', checksumVal)
print('Packeting')
receiverSocket.sendto(packet, addr)
print('Sent')
packet, addr = receiverSocket.recvfrom(bufferSize)
receivedPacket = unpacker.unpack(packet)
dataFile.close()
receiverSocket.close```
I'm not sure where to even start, so far I have this for the server side:
# Server program
from socket import *
import time
import sys
serverhost = '127.0.0.1'
serverport = 5005
buffersize = 2048
serversock = socket(AF_INET,SOCK_DGRAM)
serveraddr = (serverhost, serverport)
serversock.bind(serveraddr)
print 'Server is ready to receive'
while True:
try:
message, clientaddr = serversock.recvfrom(buffersize)
print 'Server received ', message, 'from ', str(clientaddr)
print "Server sending back " + str(message)
serversock.sendto(message, clientaddr)
except:
print 'Exception occured, closing socket'
break
serversock.close()
and this for the client side:
# Client program
from socket import *
import time
import sys
import struct
def Main():
srcip = destip = "127.0.0.1"
srcport, destport = 5005, 5000
payload = '[TESTING]\n'
tcp = make_tcp(srcport, destport, payload)
packet = tcp + payload
buffersize = 2048
addr = (destport, serverport)
clientsock = socket(AF_INET,SOCK_DGRAM)
def tcp(srcport,destport, payload, seq=123 , ackseq=0,
fin=False, syn=True, rst=False, psh=False, ack=False, urg=False,
window = 5840):
offsetres = (5 << 4) | 0
flags = (fin | (syn << 1) | (rst << 2) |
(psh << 3) | (ack << 4) | (urg << 5))
return struct.pack('HHLLBBHHH',
srcport, destport, seq, ackseq, offset_res,
flags, window, 0, 0)
data = "This is the client"
try:
start = time.time()
clientsock.sendto(data, packet, serveraddr, (destip, 0))
print "Client sent message ...", data, "... waiting for response."
response, addr = clientsock.recvfrom(buffersize)
response_id = struct.unpack('!HI', response[4:6])
end = time.time()
elapsed = end - start
print response_id
print "Elapsed time = ", elapsed
except:
print "Exception occured"
clientsock.close()
if __name__== "__main__":
Main()
I'm not sure if the TCP header is correct so far, but How do I start a message exchange? It's supposed to be sending packets over UDP with TCP features. How should I start the connection (three way handshake)?
I'm trying to write my own dns server with python code. So, I send dns request from my computer to my gateway (which i get from ipconfig-> default gateway). The request reaches to my server and when I'm trying to response, it seems like the dns response not reaching the client destination (at this case my computer).
On the client i get "Standard query response Server failure" instead of regular dns response.
What am I doing wrong? How can I fix it?
Client wireshark:
Server wireshark:
Client code:
def ConvertToDnsNameFormat(name) :
result = ""
lock = 0
name += "."
length = len(name)
for i in range(0, length) :
if name[i] == "." :
result += chr(i-lock)
while lock < i :
result += name[lock]
lock = lock + 1
lock = lock + 1
result += (chr(0))
return result
hostname= "random1231.ns.cs.colman.ac.il"
hostname = ConvertToDnsNameFormat(hostname)
format = '!HHHHHH' + str(len(hostname)) + 'sHH' # the DNS query format
dnsMessage = pack(format, 1234, 256, 1, 0, 0, 0, hostname, 1, 1) # create the massage
#my gateway
HOST_IP = "192.168.1.1"
PORT = 53
AF = socket.AF_INET
TYPE = socket.SOCK_DGRAM
PROTO = socket.IPPROTO_UDP
mySocket = socket.socket(AF, TYPE, PROTO)
mySocket.sendto(dnsMessage, (HOST_IP, PORT))
(resp, address) = mySocket.recvfrom(1024)
Server code:
I took this code from here
import socket
class DNSQuery:
def __init__(self, data):
self.data=data
self.dominio=''
tipo = (ord(data[2]) >> 3) & 15 # Opcode bits
if tipo == 0: # Standard query
ini=12
lon=ord(data[ini])
while lon != 0:
self.dominio+=data[ini+1:ini+lon+1]+'.'
ini+=lon+1
lon=ord(data[ini])
def respuesta(self, ip):
packet=''
if self.dominio:
packet+=self.data[:2] + "\x81\x80"
packet+=self.data[4:6] + self.data[4:6] + '\x00\x00\x00\x00' # Questions and Answers Counts
packet+=self.data[12:] # Original Domain Name Question
packet+='\xc0\x0c' # Pointer to domain name
packet+='\x00\x01\x00\x01\x00\x00\x00\x3c\x00\x04' # Response type, ttl and resource data length -> 4 bytes
packet+=str.join('',map(lambda x: chr(int(x)), ip.split('.'))) # 4bytes of IP
return packet
if __name__ == '__main__':
ip='192.168.1.1'
print 'pyminifakeDNS:: dom.query. 60 IN A %s' % ip
udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udps.bind(('10.10.250.40',53))
try:
while 1:
data, addr = udps.recvfrom(1024)
p=DNSQuery(data)
udps.sendto(p.respuesta(ip), addr)
print 'Respuesta: %s -> %s' % (p.dominio, ip)
except KeyboardInterrupt:
print 'Finalizando'
udps.close()
That's probably because the server is failing. Try to do a ping to random1231.ns.cs.colman.ac.il, you'll see that with that domain, the response is server failure:
So, the miniDNS program is not capturing the DNS requests. Did you try installing it on your localhost address? (127.0.0.1, say port 4567) and configure your DNS service to that address.
I have a problem with my script. For a test i want to print an src and dst ip address but the characters displayed are special and after many researches i still don't understand why ...
I'm sure this is a simply problem but i didnt get it ...
This is the output:
And this is my script:
import pcapy
import dpkt
from threading import Thread
import re
import binascii
liste=[]
listip=[]
piece_request_handshake = re.compile('13426974546f7272656e742070726f746f636f6c(?P<reserved>\w{8})(?P<info_hash>\w{20})(?P<peer_id>\w{20})')
piece_request_tcpclose = re.compile('(?P<start>\w{12})5011')
class PieceRequestSniffer(Thread):
def __init__(self, dev='eth0'):
Thread.__init__(self)
self.expr = 'udp or tcp'
self.maxlen = 65535 # max size of packet to capture
self.promiscuous = 1 # promiscuous mode?
self.read_timeout = 100 # in milliseconds
self.max_pkts = -1 # number of packets to capture; -1 => no limit
self.active = True
self.p = pcapy.open_live(dev, self.maxlen, self.promiscuous, self.read_timeout)
self.p.setfilter(self.expr)
#staticmethod
def cb(hdr, data):
eth = dpkt.ethernet.Ethernet(str(data))
ip = eth.data
#Select Ipv4 packets because of problem with the .p in Ipv6
if eth.type == dpkt.ethernet.ETH_TYPE_IP6:
return
else:
#Select only TCP protocols
if ip.p == dpkt.ip.IP_PROTO_TCP:
tcp = ip.data
try:
#Return hexadecimal representation
hex_data = binascii.hexlify(tcp.data)
except:
return
fin_flag = ( tcp.flags & dpkt.tcp.TH_FIN ) != 0
if fin_flag:
print " -------------------FIN filtered-------------------"
src_ip = ip.src
dst_ip = ip.dst
#listip.append(theip)
print "\n"
print "src_ip %s %s dst_ip %s" % (src_ip,"\n", dst_ip)
#for element in zip(str(listip),str(thedata)):
#print(element)
def stop(self):
#logging.info('Piece Request Sniffer stopped...')
self.active = False
def run(self):
while self.active:
self.p.dispatch(0, PieceRequestSniffer.cb)
sniffer = PieceRequestSniffer()
sniffer.start()
First, import socket, then use:
src_ip = socket.inet_ntoa(ip.src)
dst_ip = socket.inet_ntoa(ip.dst)
I am using this code in python to send connect request and annouce request to udp tracker,
clisocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print clisocket
connection_id = 0x41727101980
transaction_id = randrange(1, 65535)
info_hash = info_hash
peer_id = "ABCDEFGHIJKLMNOPQRST"
action = 0
downloaded = 0
left = 0
uploaded = 0
event = 2
ip = 0
key = 0
num_want = 10
port = 9999
connect_pack = struct.pack(">QLL", connection_id, action, transaction_id)
clisocket.sendto(connect_pack, ("tracker.publicbt.com", 80))
res = clisocket.recv(16)
action, transaction_id, connection_id = struct.unpack(">LLQ", res)
announce_pack = struct.pack(">QLL20s20sQQQLLLLH", connection_id, 1, transaction_id, info_hash, peer_id, downloaded, left, uploaded, event, ip, key, num_want, port)
clisocket.sendto(announce_pack, ("tracker.publicbt.com", 80))
res = clisocket.recv(1024)
action = struct.unpack("!LLLLLLH", res[:26])
print action
I am getting this response,
(1, 56347, 1782, 0, 1, 838084381, 9999)
as per the protocol specifications [link] : http://www.bittorrent.org/beps/bep_0015.html
I am getting
annouce i.e 1
transaction_id i.e 56347 which is same as the generated transaction_id
but in place of port I am getting the port I am sending in the announce request and in place of IP I am getting 838084381.
Is this the response that I should get from the udp tracker?
How to parse the ip of the peers from this?
The IP address is returned in a 32-bit packed format. You can convert it to a dotted-quad string representation like this:
import socket, struct
ip = socket.inet_ntoa(struct.pack('!L', 838084381))
print ip; # prints 49.244.39.29
Reference