How to string format subprocess output? - python

Below is my nslookup result using subprocess module in Python.
b'Server: server.internal\r\nAddress: 192.168.0.2\r\n\r\nName:
www.google.com\r\nAddresses: 2404:6800:4007:800::2004\r\n\t
216.58.197.68\r\n\r\n'
Could someone please help me to format the result as below.
Server: server.internal
Name: www.google.com
DNS: 192.168.0.2
Addresses: 2404:6800:4007:800::2004 , 216.58.197.68

You can do it by parsing the lines of the nslookup result into a dictionary, and then using it to format the output.
nslookup = (b'Server: server.internal\r\nAddress: 192.168.0.2\r\n\r\n'
b'Name: www.google.com\r\nAddresses: 2404:6800:4007:800::2004\r\n'
b'\t216.58.197.68\r\n\r\n')
info = {}
for line in nslookup.decode().splitlines():
tokens = line.split()
if len(tokens) == 2:
if tokens[0] == 'Addresses:':
info.setdefault('Addresses', []).append(tokens[1]) # Without ":"
else:
info[tokens[0].rstrip(':')] = tokens[1]
elif len(tokens) == 1:
info['Addresses'].append(tokens[0])
info['Addresses'] = ', '.join(info['Addresses']) # Format and convert to string.
print('''\
Server: {Server}
Name: {Name}
DNS: {Address}
Addresses: {Addresses}'''.format(**info))
Output:
Server: server.internal
Name: www.google.com
DNS: 192.168.0.2
Addresses: 2404:6800:4007:800::2004, 216.58.197.68

You could use Python's unicode_escape to help convert it. The result could then be split into lines and reassembled as follows:
nslookup = b'Server: server.internal\r\nAddress: 192.168.0.2\r\n\r\nName: www.google.com\r\nAddresses: 2404:6800:4007:800::2004\r\n\t216.58.197.68\r\n\r\n'
lines = [line.strip('\t').replace(' ', ' ') for line in nslookup.decode('unicode_escape').splitlines()]
print('\n'.join([lines[0], lines[3], lines[1], '{} , {}'.format(lines[4], lines[5])]))
Giving you:
Server: server.internal
Name: www.google.com
Address: 192.168.0.2
Addresses: 2404:6800:4007:800::2004 , 216.58.197.68
Address: could be replaced by DNS: by a final .replace()

Related

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.

How to pass inputs from file to dns.resolver.Resolver.query() from file in dns python?

I am writing a code to pass domain name and ip address from file to dns resolver query. But it does not seem to be working
import dns.resolver
import os
import sys
d = open(str(sys.argv[1]),'r') #contains the domain name list
ip = open(str(sys.argv[2]),'r') # contain the list of ip address as dns resolver
domain_list = d.readlines()
ip_list = ip.readlines()
my_resolver = dns.resolver.Resolver()
output_f = open("output.txt",'a')
for nameserv in ip_list:
my_resolver.nameservers = [nameserv]
for domain in domain_list:
try:
answer = my_resolver.query(domain)
entry = "server : " + " " + nameserv + " " + "query_result " + str(answer) + '\n'
output_f.write(entry)
except :
print domain,nameserv
print "no domain"
d.close()
ip.close()
output_f.close()
My ip address list contains 8.8.8.8 and 127.0.1.1 which are both valid dns resolvers. domain list contain www.facebook.com,www.urltrends.com etc
Still i am getting error that no domain exists.
readlines() also reads the trailing \n, which then gets passed to the resolver. Try this instead:
my_list = open(filename, 'r').read().splitlines()

Parsing IP address and port in python

Using python, I'd like to accomplish two things:
Need to split an ipv6 address and port combination in the format [fec2::10]:80 to fec2::10 and 80.
Given an IP address and port combination, I need to determine if the IP is a v4 or v6 address. Eg: 1.2.3.4:80 and [fec2::10]:80
Please suggest a way to do it.
Thanks!
Sample code:
#!/usr/bin/env python
def main():
server = "[fec1::1]:80"
if server.find("[", 0, 2) == -1:
print "IPv4"
ip, port = server.split(':')
else:
print "IPv6"
new_ip, port = server.rsplit(':', 1)
print new_ip
ip = new_ip.strip('[]')
print ip
print port
if __name__ == '__main__':
main()
This works for all cases except when the input is specified without a port. Eg: 10.78.49.50 and [fec2::10]
Any suggestions to address this?
Assuming your_input is like "[fec2::10]:80" or "1.2.3.4:80", it is easy to split the port and find out the ip address:
#!/usr/bin/env python3
from ipaddress import ip_address
ip, separator, port = your_input.rpartition(':')
assert separator # separator (`:`) must be present
port = int(port) # convert to integer
ip = ip_address(ip.strip("[]")) # convert to `IPv4Address` or `IPv6Address`
print(ip.version) # print ip version: `4` or `6`
You can use urlparse (called urllib.parse in 3.x) to separate the URL into each of its components:
>>> from urlparse import urlparse
>>> ipv4address = urlparse("http://1.2.3.4:80")
>>> ipv4address
ParseResult(scheme='http', netloc='1.2.3.4:80', path='', params='', query='', fragment='')
>>> ipv6address = urlparse("http://[fec2::10]:80")
>>> ipv6address
ParseResult(scheme='http', netloc='[fec2::10]:80', path='', params='', query='', fragment='')
Then you can split the port off by finding the index of the last colon using rfind:
>>> ipv4address.netloc.rfind(':')
7
>>> ipv4address.netloc[:7], ipv4address.netloc[8:]
('1.2.3.4', '80')
>>> ipv6address.netloc.rfind(':')
10
>>> ipv6address.netloc[:10], ipv6address.netloc[11:]
('[fec2::10]', '80')
Identifying which type it is should then be as simple as if ':' in that_split_tuple[0], right? (Not 100% sure because it's been a while since I learned about how to write IPv6 addresses in URLs.)
Finally, removing the brackets from your IPv6 address is simple, there are many ways to do it:
>>> ipv6address.netloc[:10].replace('[', '').replace(']', '')
'fec2::10'
>>> ipv6address.netloc[:10].strip('[]')
'fec2::10'
Edit: since you expressed concern about not always having port numbers, you could simplify significantly by using a regular expression:
>>> import re
>>> f = lambda(n): re.split(r"(?<=\]):" if n.startswith('[') else r"(?<=\d):", n)
>>> f(ipv4address.netloc)
['1.2.3.4', '80']
>>> f(ipv6address.netloc)
['[fec2::10]', '80']
>>> f("1.2.3.4")
['1.2.3.4']
>>> f("[fec2::10]")
['[fec2::10]']
(I'm having trouble being more clever with my regular expression, hence the inline ternary.)
This is the code I came up with. It looks lengthy and laborious, but it addresses all possible input scenarios. Any suggestion to condense/better it is most welcome :)
#!/usr/bin/env python
import optparse
def main():
server = "[fec1::1]:80"
if server.find("[", 0, 2) == -1:
print "IPv4"
if server.find(":", 0, len(server)) == -1:
ip = server
port = ""
else:
ip, port = server.split(':')
else:
print "IPv6"
index = server.find("]", 0, len(server))
if index == -1:
print "Something wrong"
new_ip = ""
port = ""
else:
if server.find(":", index, len(server)) == -1:
new_ip = server
port = ""
else:
new_ip, port = server.rsplit(':', 1)
print new_ip
ip = new_ip.strip('[]')
print ip
print port
if __name__ == '__main__':
main()

I want to match a newline character followed by a string using regular expression in python

Device ID: xyz
Entry address(es):
IP address: 10.3.10.46
Platform: WS-x, Capabilities: Switch IGMP
Interface: GigabitEthernet9/33, Port ID (outgoing port): GigabitEthernet0/2
Holdtime : 177 sec
Management address(es):
IP address: 10.3.10.46
above is a snipet from a file.From among the above i want to collect the ip address by matching only the 2 lines below.
Entry address(es):
IP address: 10.3.10.46
or
Management address(es):
IP address: 10.3.10.46
The regular expression i have written is as follows which does not work and i am not able to resolve how i can show the new line after "address(es):" in my regular expression.
f = open(fileName)
for line in f:
matchObj1 = re.match(r'Entry address\(es\):\s+IP address: ([0-9.]+)', line)
if matchObj1:
print "IP Address = ", matchObj1.group(1)
matchObj2 = re.match(r'Entry address\(es\):\s+IP address: ([0-9.]+)', line)
if matchObj2:
print "IP Address = ", matchObj2.group(1)
Please Help. Thank you.
You need to use re.search instead of re.match, re.match is used for matching from the start of string:
>>> s = 'Device ID: xyz\nEntry address(es): \n IP address: 10.3.10.46\n Platform: WS-x, Capabilities: Switch IGMP \n Interface: GigabitEthernet9/33, Port ID (outgoing port): GigabitEthernet0/2\n Holdtime : 177 sec'
>>> re.search(r'Entry address\(es\):\s+IP address: ([0-9.]+)', s).group(1)
'10.3.10.46'
search() vs. match():
re.match() checks for a match only at the beginning of the string,
while re.search() checks for a match anywhere in the string.
You don't need to use regular expressions for this. Your input looks like the output of a configuration file or a program, and easy to parse.
def get_addresses(fname):
addresses = {}
with open(fname) as f:
lines = [l.strip().lower() for l in f]
for i, line in enumerate(lines):
if line.startswith("ip address"):
ip = line.split(": ")[1]
address_type = lines[i-1]
if address_type == "entry address(es):":
addresses["entry"] = ip
elif address_type == "management address(es):":
addresses["management"] = ip
# Add additional address type handling here
return addresses

Converting IPv4 Address to a Hex IPv6 Address in Python

Q: Write a program that prompts the user for an IP address then converts this to a base 10, binary and hex value. The program then converts the hex value to an RFC3056 IPv6 6to4 address.
I have the base 10 and binary parts working but I can't seem to get my head around the hex part. Can the format string method be used somehow to accomplish the same thing? Or would I need to import the ipaddress module in this case?
#!/usr/bin/python3
ip_address = input("Please enter a dot decimal IP Address: ")
"""This part converts to base 10"""
ListA = ip_address.split(".")
ListA = list(map(int, ListA))
ListA = ListA[0]*(256**3) + ListA[1]*(256**2) + ListA[2]*(256**1) + ListA[3]
print("The IP Address in base 10 is: " , ListA)
"""This part converts to base 2"""
base2 = [format(int(x), '08b') for x in ip_address.split('.')]
print("The IP Address in base 2 is: ", base2)
"""This part converts to hex"""
hexIP = []
[hexIP.append(hex(int(x))[2:].zfill(2)) for x in ip_address.split('.')]
hexIP = "".join(hexIP)
print("The IP Address in hex is: " , hexIP)
EDIT: Managed to convert the IP Address to hex value. Now how do I convert this hex value into IPv6 address?
>>> ip_address = '123.45.67.89'
>>> numbers = list(map(int, ip_address.split('.')))
>>> '2002:{:02x}{:02x}:{:02x}{:02x}::'.format(*numbers)
'2002:7b2d:4359::'
In Python 3.3 you could use ipaddress module to manipulate IPv4, IPv6 addresses:
#!/usr/bin/env python3
import ipaddress
# get ip address
while True:
ip4str = input("Enter IPv4 (e.g., 9.254.253.252):")
try:
ip4 = ipaddress.IPv4Address(ip4str)
except ValueError:
print("invalid ip address. Try, again")
else:
break # got ip address
# convert ip4 to rfc 3056 IPv6 6to4 address
# http://tools.ietf.org/html/rfc3056#section-2
prefix6to4 = int(ipaddress.IPv6Address("2002::"))
ip6 = ipaddress.IPv6Address(prefix6to4 | (int(ip4) << 80))
print(ip6)
assert ip6.sixtofour == ip4
# convert ip4 to a base 10
print(int(ip4))
# convert ip4 to binary (0b)
print(bin(int(ip4)))
# convert ip4 to hex (0x)
print(hex(int(ip4)))
If you just want to use the IPv4 addresses in an IPv6 context (e.g. by passing to socket.connect() created using the socket.AF_INET6 address family), you can just use the syntax described in RFC4291, Section 2.2:
>>> import socket
>>> a = '10.20.30.40'
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
>>> s.connect(('2002::' + a, 9))
I.e. just prepend ::ffff: to the IPv4 address and you get a valid 6to4 address. If you instead want to convert this address to the more common hexadecimal form, I suggest using the standard library ipaddress module you mentioned:
>>> import ipaddress
>>> a = '10.20.30.40'
>>> print(ipaddress.IPv6Address('2002::' + a).compressed)
'2002::a14:1e28'
Before referring to the solution, have a look at this doc for conversion and convention of ipv6 representation.
def ipconversion4to6(ipv4_address):
hex_number = ["{:02x}".format(int(_)) for _ in address.split(".")]
ipv4 = "".join(hex_number)
ipv6 = "2002:"+ipv4[:4]+":"+ipv4[4:]+"::"
return ipv6

Categories

Resources