Remove Duplicate IP Addresses with Scapy - python

I have a script to listen for incoming traffic and print out only the string “IP 1.1.1.1 53" when a packet hits the line. But now that I’m doing IP resolve on the IPs, I need to access the “ip_src” variable and only do the geolocation once on each ip, rather than resolve the same IP over and over as they come in. My current code is:
#!/usr/bin/python3
from scapy.all import *
import ipinfo
def print_summary(pkt):
if IP in pkt:
ip_src=pkt[IP].src
if UDP in pkt:
udp_sport=pkt[UDP].sport
access_token = ''
handler = ipinfo.getHandler(access_token)
match = handler.getDetails(ip_src)
c = match.details.get('city')
s = match.details.get('region')
strang = ("IP " + str(ip_src) + " " + str(udp_sport) + " " + str(c) + ", " + str(s))
print(strang)
sniff(filter="",prn=print_summary)
As you can see the “print_summary” function is called by “prn” which is called for each pkt. I basically want to mimic the functionality of uniq and sort, since they can successfully filter out duplicates from a file, but I’d like to have it all in one script.
EDIT - Trying Set():
So using the code:
from scapy.all import *
def print_summary(pkt):
if IP in pkt:
ip_src=pkt[IP].src
if UDP in pkt:
udp_sport=pkt[UDP].sport
lines_set = set(ip_src)
strang = ("IP " + str(ip_src) + " " + str(udp_sport))
if ip_src not in lines_set:
for line in lines_set:
print(line)
sniff(filter="",prn=print_summary)
I get the output: (in the terminal each character has a trailing newline)
2 . 3 5 8 0 1 2 . 4 8 0 1 . 6

This adds a set variable to keep track of which addresses you have already seen.
#!/usr/bin/python3
from scapy.all import *
import ipinfo
seen = set()
def print_summary(pkt):
if IP in pkt:
ip_src=pkt[IP].src
if UDP in pkt and ip_src not in seen:
seen.add(ip_src)
udp_sport=pkt[UDP].sport
access_token = ''
handler = ipinfo.getHandler(access_token)
match = handler.getDetails(ip_src)
c = match.details.get('city')
s = match.details.get('region')
strang = ("IP " + str(ip_src) + " " + str(udp_sport) + " " + str(c) + ", " + str(s))
print(strang)
sniff(filter="ip",prn=print_summary)
I also changed the indentation of the second if to avoid getting a traceback if somehow you would receive a packet which doesn't have the IP member; though I also updated the filter expression to hopefully prevent that from ever happening in the first place.

Related

Trying To Scan IP For Getting Domain Name In Python With Socket

I am trying to scan domain name from ip address.
That's why i took a input from file and split that, amd changing the last 3digit with loop . and checking all random ip. But It Shows Nothing. And there is a valid ip with domain.
f = open('ip.txt', 'r')
r = f.readline()
f.close()
ips = r.split(".")
ipc = ips[0] + "." + ips[1] + "." + ips[2] + "."
for i in range(0, 256):
ipm = ipc + str(i)
ip = str('"' + ipm + '"')
try:
socket.gethostbyaddr(ip)
except:
pass
Your indentation here is wrong, try this:
for i in range(0,256):
ipm=ipc+str(i)
ip=str('"'+ipm+'"')
try:
socket.gethostbyaddr(ip)
except:
pass
Edit: I also suspect that you can simply do ip = str(ipm), without needing to add the extra double quotes.

Python socket.bind() to host does not show incoming packets with SIO_RCVALL while sniffing for traffic on an interface

I'm attempting to read incoming/outgoing TCP packets through an interface on the host for a project I'm working on. I really want this to be done using sockets instead of using a library like scapy or pypcap. To have a better understanding of what is happening as well as more control over what is happening. This is on a Windows10 system.
import socket
import threading
from PacketParse import PacketParse
host = socket.gethostbyname(socket.gethostname())
sniff = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
sniff.bind((host, 0))
#include ip headers - IP PROTOCOL, IP HEADER INCLUDE
sniff.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
#receive all packages - INPUT OUTPUT CONTROL
sniff.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
def start_sniffing():
while True:
raw_packet = sniff.recvfrom(2000)
packet = PacketParse(raw_packet)
if packet:
print(packet.src_addr + ":" + str(packet.src_port) + " --> " + packet.dst_addr + ":" + str(packet.dst_port) + " Protocol: " + packet.ip_prot + "(" + str(packet.ip_prot_raw) + ")")
print("Data(" + str(packet.data_size) + "): " + str(packet.data))
#file.write(packet.src_addr + ":" + str(packet.src_port) + " --> " + packet.dst_addr + ":" + str(packet.dst_port) + " Protocol: " + packet.ip_prot + "(" + str(packet.ip_prot_raw) + ")")
#file.write("Data(" + str(packet.data_size) + "): " + str(packet.data))'''
file = open("dump.txt", "a")
t = threading.Thread(target=start_sniffing)
t.start()
t.join()
file.close()
sniff.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
PacketParse is a class I made to 'unpack' the packet. I've been using Python documentation for most of this script and tutorials for sniffing packets from many sources.
from struct import unpack
class PacketParse:
def __init__(self, packet):
self.extract(packet)
def extract(self, packet):
# extract ip header
packet = packet[0]
self.packet_raw = packet
'''
eth_raw = packet[:14]
eth_hdr = unpack('!6s6sH', eth_raw)
self.eth_prot = socket.ntohs(eth_hdr[2])
self.src_mac =
'''
ip_raw = packet[0:20]
ip_hdr = unpack('!BBHHHBBH4s4s', ip_raw)
#self.ip_length = ip_hdr[5]
self.ip_prot_raw = ip_hdr[6]
self.ip_prot = self.ip_prot_parse(ip_hdr[6])
self.src_addr = socket.inet_ntoa(ip_hdr[8])
self.dst_addr = socket.inet_ntoa(ip_hdr[9])
version = ip_hdr[0] >> 4
ihl_length = version & 0xF
iph_len = ihl_length * 4
tcp_raw = packet[20:40]
tcp_hdr = unpack('!HHLLBBHHH', tcp_raw)
self.src_port = tcp_hdr[0]
self.dst_port = tcp_hdr[1]
self.seq_num = tcp_hdr[2]
self.ack_num = tcp_hdr[3]
doff_reserved = tcp_hdr[4]
tcp_length = doff_reserved >> 4
header_size = (iph_len) + (tcp_length * 4)
self.data_size = len(packet) - header_size
self.data = packet[header_size:]
def ip_prot_parse(self, num):
return {
1: 'ICMP',
6: 'TCP',
17: 'UDP',
}.get(num, "Unknown")
The issue is this only shows packets being sent out from this host. Incoming packets are not displayed. A different script I've tried using scapy is capable of displaying incoming packets as well. Why is this happening? SIO_RCVALL should be allowing ALL packets being touched by the interface to be seen. I haven't tried a Linux equivalent of this script... so I don't know if the problem is specific on Windows. Most TCP reading scripts I've found have been Linux specific.
Alright... so it seems the problem was my firewall. When I turn it off, I can see all incoming packets just fine. That was a bit annoying. I believe there is a python library that allows you to edit firewall settings.
https://github.com/austin-taylor/bluewall
I haven't played around with it yet... it could be interesting. I haven't read into it enough yet to understand if this is what it seems. I believe it only gives you the configuration on Windows without changing anything. It could be fun on a Linux system.

Using Python 3.4 to Ping a network then report address, dns name, etc.

I wanted to create a Python program that does several things. Ping all addresses in a predefined network, gather the DNS information, write a file with IP address, DNS name, ping fail or pass, date. Then run and email the resulting file to myself once a week, every Friday. I have created this program and will post my own answer. I am new to Python and was able to get this written with the help from other answers posted on this site. Thanks to all those who contributed answers on this site. Hope the answer I post will help someone else.
#!/usr/bin/python3.4
#Above statement makes sure you are using version 3.4
#when multiple versions are installed. has to be the 1st line.
# Import modules
import subprocess
import socket
import errno
import time
import datetime
import ipaddress
today = datetime.date.today()
# define DNS lookup and error handling
# return none,none,none needed otherwise if no DNS record
# the routine errors out and the program stops
def lookup(addr):
try:
return socket.gethostbyaddr(addr)
except socket.herror:
return None, None, None
# Prompt the user to input a network address
# commented out the prompt for input so it can run unattended
# net_addr = input("Enter a network address in CIDR
format(ex.192.168.1.0/24): ")
net_addr = ('192.168.1.0/24')
# Create the network
ip_net = ipaddress.ip_network(net_addr)
# Get all hosts on that network
all_hosts = list(ip_net.hosts())
# Configure subprocess to hide the console window
# removed code due to errors not windows linux
# setup online and offline count variables
offCnt = 0
onCnt = 0
# Open file and or create if it doesn't exist.
# file to be overwritten each time the program is run.
file = open("lab-ip.doc","w")
# For each IP address in the subnet,
# run the ping command with subprocess.popen interface
# Grab the DNS information for each IP address
# Print to console add counters and write to file.
for i in range(len(all_hosts)):
output = subprocess.Popen(['ping', '-c', '2', str(all_hosts[i])],
stdout=subprocess.PIPE).communicate()[0]
name,alias,addresslist = lookup(str(all_hosts[i]))
if "Destination Host Unreachable" in output.decode('utf-8'):
print(str(all_hosts[i]), " Ping Fail", str(name), today)
file.write(str(all_hosts[i]) + " Ping Fail - " + str(name) + " " + str(today) + "\n")
offCnt = offCnt + 1
elif "Request timed out" in output.decode('utf-8'):
print(str(all_hosts[i]), " Ping Fail", str(name), today)
file.write(str(all_hosts[i]) + " Ping Fail - " + str(name) + " " + str(today) + "\n")
offCnt = offCnt + 1
else:
print(str(all_hosts[i]), " Ping Pass", str(name), today)
file.write(str(all_hosts[i]) + " Ping Pass - " + str(name) + " " + str(today) + "\n")
onCnt = onCnt + 1
print ("Pass count = ", str(onCnt))
file.write("Pass count = " + str(onCnt))
print ("Fail count = ", str(offCnt))
file.write(" Fail count = " + str(offCnt))
file.close()
# Import yagmail for the actual sending function
import yagmail
yag = yagmail.SMTP('Gmail-id', 'gmail-pswd')
yag.send('email#email.com', subject = "Lab-ip List",contents = 'lab-ip.doc')
yag.send('email2#email2.com', subject = "Lab-ip List",contents = 'lab-ip.doc')
#end

Strip TZSP Encapsulation - live traffic

I'm creating a log server, that write incoming and outgoing connections (any type) to a TXT file . everything is working fine and here is my code :
from scapy.all import *
import datetime
from threading import Thread
from Queue import Queue, Empty
from scapy.layers.dns import DNS, DNSQR
firstime = 0
times = time.time()+86400
def print_summary(pkt):
global firstime
global times
if IP in pkt:
ip_src=pkt[IP].src
ip_dst=pkt[IP].dst
else:
ip_src="Null"
ip_dst="Null"
mac_src="Null"
mac_dst="Null"
if TCP in pkt:
tcp_sport=pkt[TCP].sport
tcp_dport=pkt[TCP].dport
else:
tcp_sport="Null"
tcp_dport="Null"
if DNSQR in pkt:
dns = pkt.qd.qname
else:
dns = "NULL"
if Ether in pkt:
mac_src = pkt[Ether].src
mac_dst = pkt[Ether].dst
else:
mac_src = "Null"
mac_dst = "Null"
Clog = " IP src: " + str(ip_src) +" ,MAC src: " + str(mac_src) + " , IP dst: " + str(ip_dst) +" ,MAC dst: "+str(mac_dst)+" ,TCP sport: " + str(tcp_sport) + ",TCP dport: " + str(tcp_dport) +", Time: " + str(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(pkt.time))) + " Dns: "+dns
if(times > pkt.time):
if(firstime == 0):
f = open("/root/Desktop/LOG-SERVER/"+time.strftime('%Y-%m-%d %H:%M:', time.localtime(time.time()))+".txt",'a')
f.write(Clog+"\n")
f.close()
else:
f.write(Clog+"\n")
f.close()
else:
f = open("/root/Desktop/LOG-SERVER/"+time.strftime('%Y-%m-%d %H:%M:', time.localtime(time.time()))+".txt",'a')
f.write(Clog+"\n")
f.close()
times=times+86400
def startsnif():
sniff(prn=print_summary, store=0)
# you can filter with something like that
#if ( ( pkt[IP].src == "192.168.0.1") or ( pkt[IP].dst == "192.168.0.1") ):
# print("!")
#def writing(log,indexp):
#if(indexp == 0):
#f = open("/root/Desktop/LOG-SERVER/"+time.strftime('%Y-%m-%d %H:%M:', time.localtime(time.time()))+".txt",'a')
#f.write(log+"\n")
#f.close()
#else:
#f.write(log+"\n")
#f.close()
thread.start_new_thread(startsnif,());
while 1:
pass
# or it possible to filter with filter parameter...!
#sniff(filter="ip and host 192.168.0.1",prn=print_summary)
output is:
IP Src: 192.168.10.1 MAC Src: 54:55:12:FC:2D:CA IP Dst:192.168.10.15 MAC Src: 54:55:12:FC:1F:3A TCP sport: 80 TCP dport: 51233 Time:2015-12-16 13:25:11 DNS:Null(IF available DNS Name)
the problem is that the company got mikrotics, mikrotics mirror traffic through a technique called TZSP Sniff which encapsulate the packet with the IP of the router and MAC of the router IP of the destination PC MAC of the destination pc, i was searching and i couldn't find any appropriate solution but i read that you need to strip first 5 bytes of a packet.
is there a way to strip the TZSP encapsulation live(without saving PCAP), could you please explain the process because I'm new to this stuff?
please if you have any question ask I'm not very good in explaining stuff.
Thank you!
After examining the binary of the TZSP packet header it appears that TZSP strip original mac address after adding it's own, so the project was closed thank you for the help.

Creating a simple IRC bot in python. Having trouble

So a few hours ago I decided to try my hands on sockets with python and build a simple irc bot. So far I'm having some trouble getting it connected to the server. I get the following erros:
b":irc.ku.cx 439 * :Please wait while we process your connection.\r\n:irc.ku.cx NOTICE AUTH :*** Couldn't look up your hostname (cached)\r\n"
b':irc.ku.cx NOTICE AUTH :*** Checking Ident\r\n'
b':irc.ku.cx NOTICE AUTH :*** No Ident response\r\n'
After that it stalls out. But about a minute of it running I suddenly get an endless amount of b"", each in a new line (probably something to do with the while loop in the code). This is my code:
import socket
server = 'irc.rizon.net'
channel = '#linux'
nick = 'MyBot'
port = 6667
ircsock = socket.socket()
ircsock.connect((server, port))
ircsock.send(bytes('"NICK " + nick', 'UTF-8'))
ircsock.send(bytes('"USER " + nick + " " + nick + " " + nick + " :" + nick', 'UTF-8'))
while True:
data = ircsock.recv(2048)
print (data)
if data.find(b"PING") != -1:
ircsock.send(b"PONG :" + data.split(':')[1])
Thanks for any help you guys can provide.
As icktoofay said, there are extra quotes in your code. Also, in IRC you need to add a line break (\r\n) to the end of every command.
Replace these lines:
ircsock.send(bytes('"NICK " + nick', 'UTF-8'))
ircsock.send(bytes('"USER " + nick + " " + nick + " " + nick + " :" + nick', 'UTF-8'))
with
ircsock.send(bytes("NICK " + nick + "\r\n", 'UTF-8'))
ircsock.send(bytes("USER " + nick + " " + nick + " " + nick + " :" + nick + "\r\n", 'UTF-8'))
and it should work.
By the way, I recommend using socket.makefile() instead, which handles buffering and encoding for you. Here's your code modified to use the file interface:
import socket
server = 'irc.rizon.net'
channel = '#linux'
nick = 'MyBot'
port = 6667
ircsock = socket.socket()
ircsock.connect((server, port))
handle = ircsock.makefile(mode='rw', buffering=1, encoding='utf-8', newline='\r\n')
print('NICK', nick, file=handle)
print('USER', nick, nick, nick, ':'+nick, file=handle)
for line in handle:
line = line.strip()
print(line)
if "PING" in line:
print("PONG :" + line.split(':')[1], file=handle)
Here, I use the print function which inserts spaces and newlines automatically.

Categories

Resources