Using regex, get values and create dictionary - python

First time posting an ongoing learning about Python.
Currently, I'm stuck with a very simple thing: I've a router's output - a list called "interfaces" - which, when printed, looks like this:
set interfaces ge-0/0/0 unit 0 family inet address 192.168.15.66/24
set interfaces ge-0/0/1 unit 0 family inet dhcp
set interfaces ge-0/0/2 unit 0 family inet address 1.1.1.1/30
set interfaces ge-0/0/2 unit 0 family inet address 192.168.99.1/30
Using re module (findall), I'm finding and matching some keywords that I need, like this:
pattern1 = re.compile(r'ge.{1,7}')
pattern2 = re.compile(r'dhcp')
matched1 = pattern1.findall(interfaces)
matched2 = pattern2.findall(interfaces)
At this point, question is: If the line(?) of this router output contains the word "dhcp", I would like to save/store that value and grab the interface name/number too. In the example above, the interface cointaining "dhcp" is 'ge-0/0/1'. Do you guys have an idea if i'm going on the right path?
Is the model (get two regex) useful, to then merge both value into a dictionary, to then print using return?
How can I parse the rest of router code lines, to look for this "dhcp" value and then if no match can return a "none" or "not present" output?
Expected output will look like this (I'm using "return tabulate" to print the output):
| interface | service |
|-------------+------------|
| ge-0/0/0 | none |
| ge-0/0/1 | dhcp |
| ge-0/0/2 | none |
Any guidance, will be welcomed.
Thanks.
EDIT: Thanks both for your answers so far. I'm adding more info since probably is key.
The way I get that router output is using SaltStack integrated modules. I'm running that python file from the Salt Master, using the following syntax:
interfaces = __salt__['net.cli']('show configuration interfaces | display set', format='xml')['out']['show configuration interfaces | display set']
I sincerely hope that output is in fact a list.
In the meantime, I did another try using the following below:
def dhcp():
interfaces = __salt__['net.cli']('show configuration interfaces | display set', format='xml')['out']['show configuration interfaces | display set']
pattern = re.findall(r'ge.{1,7}', interfaces)
pattern1 = re.findall(r'dhcp', interfaces)
return pattern, pattern1
The output was this:
outright ~  sudo salt 'vsrx1' red.dhcp
vsrx1:
|_
- ge-0/0/0
- ge-0/0/0
- ge-0/0/0
- ge-0/0/0
- ge-0/0/1
- ge-0/0/2
- ge-0/0/2
|_
- dhcp
Printing the list alone (using --> return("List is: " + str(pattern)) )
outright ~  sudo salt 'vsrx1' red.dhcp
vsrx1:
List is: ['ge-0/0/0 ', 'ge-0/0/0 ', 'ge-0/0/0 ', 'ge-0/0/0 ', 'ge-0/0/1 ', 'ge-0/0/2 ', 'ge-0/0/2 ']
I do apologies if the way to express the issue is technically poor. I'm still learning the terminology in general.

You seem to me that you are on the right track. Here is my interpretation of what I think you are asking for. Hope this helps.
Note: I did this through my phone, so please excuse incorrect indentations
import re
s = ["set interfaces ge-0/0/0 unit 0 family inet address 192.168.15.66/24",
"set interfaces ge-0/0/1 unit 0 family inet dhcp", "set interfaces ge-0/0/2 unit 0 family inet address 1.1.1.1/30",
"set interfaces ge-0/0/2 unit 0 family inet address 192.168.99.1/30"]
print("interfaces | services")
mydict ={}
def parse_addresses():
for i in s:
interface = re.search(r"ge.{1,7}", i)
if "dhcp" in i:
service = "dhcp"
mydict.setdefault("router",{interface.group(): service})
else:
service = "None"
print(f"{interface.group()} | {service}")
if bool(mydict):
return mydict
return "None"
print(parse_addresses())

I am not sure how you get the router's output. But this should work
If your data is in this form
interface_list = ['set interfaces ge-0/0/0 unit 0 family inet address 192.168.15.66/24',
'set interfaces ge-0/0/1 unit 0 family inet dhcp',
'set interfaces ge-0/0/2 unit 0 family inet address 1.1.1.1/30',
'set interfaces ge-0/0/2 unit 0 family inet address 192.168.99.1/30']
Then
interface_dict = {}
for element in interface_list:
element_list = element.split(" ")
if element_list[7] =='dhcp':
interface_dict[element_list[2]] = 'dhcp'
else:
interface_dict[element_list[2]] = 'none'
print(interface_dict)
will give you
{'ge-0/0/0': 'none', 'ge-0/0/1': 'dhcp', 'ge-0/0/2': 'none'}
You can then change the dictionary to the dataframe
import pandas as pd
df = pd.Series(interface_dict).to_frame().reset_index().rename(columns={'index':'interface', 0:'service'})
df
interface service
0 ge-0/0/0 none
1 ge-0/0/1 dhcp
2 ge-0/0/2 none

Thanks to all who viewed and oriented me in several possible directions.
I'm answering to my own question (90% at least). My final script follows (And yes, I know that my code can be 100% improved, but is what I did to reach my goal):
def final():
interfaces = []
output_table1 = []
output_table2 = []
interfaces = __salt__['net.cli']('show configuration interfaces | display set', format='xml')['out']['show configuration interfaces | display set']
# Saving output into a file for further use
with open("/srv/salt/_modules/aaa.txt", "w") as file:
file.write(interfaces)
# Regex patterns to match things
regex1 = re.compile(r'(ge.{1,7}.{7}).*?(?=sampling)')
match_reg1 = regex1.finditer(interfaces)
regex2 = re.compile(r'ge.{1,7}.{7}')
match_reg2 = regex2.finditer(interfaces)
# IF stataments and FOR, to match and append items
if match_reg1:
output_table1.insert(0, "Sampled interfaces")
for match1 in match_reg1:
output_table1.append(match1.group(1))
if match_reg2:
output_table2.insert(0, "Not sampled interfaces")
for match2 in match_reg2:
output_table2.append(match2.group())
# Differences between two tables:
difference_list = []
for item in output_table2:
if item not in output_table1:
difference_list.append(item)
final = []
final.insert(0, "To enable sampling, insert the following on target device")
for line in difference_list:
final.append("set interfaces " + line + "family inet sampling [input/output]")
return output_table1, difference_list, final
After above, my output was:
terminal# sudo salt 'vsrx1' red.final
vsrx1:
|_
- Sampled interfaces
- ge-0/0/1 unit 0
- ge-0/0/1 unit 0
|_
- Not sampled interfaces
- ge-0/0/0 descrip
- ge-0/0/0 unit 0
- ge-0/0/2 unit 0
- ge-0/0/2 unit 0
|_
- To enable sampling, insert the following on target device
- set interfaces Not sampled interfacesfamily inet sampling [input/output]
- set interfaces ge-0/0/0 descripfamily inet sampling [input/output]
- set interfaces ge-0/0/0 unit 0 family inet sampling [input/output]
- set interfaces ge-0/0/2 unit 0 family inet sampling [input/output]
- set interfaces ge-0/0/2 unit 0 family inet sampling [input/output]
Please remember that I'm using Saltstack proxy minions to pull information from that Juniper vSRX device. I now need to practice more REGEX to remove all unnecesary output data and be more accurated on what I want to see, like the example above (is still dirty), but the basic goal was achived.
Another challenge that I had at the beginning was to understand the output of that "interfaces = salt['net.cli']('show configuration interfaces..." was because I thought every router command line was an item/line inside my list. When saving it in "aaa.txt" file and then printing it, it was printed different from what I had in mind:
This is the file opened by VisualCode (file called aaa.txt):
set interfaces ge-0/0/0 description vsrx1_descr_test
set interfaces ge-0/0/0 unit 0 family inet address 192.168.15.66/24
set interfaces ge-0/0/1 unit 0 family inet sampling input
set interfaces ge-0/0/1 unit 0 family inet sampling output
set interfaces ge-0/0/1 unit 0 family inet dhcp
set interfaces ge-0/0/2 unit 0 family inet address 1.1.1.1/30
set interfaces ge-0/0/2 unit 0 family inet address 192.168.99.1/30
This is the file printed by the function:
terminal# sudo salt 'vsrx1' red.final
vsrx1:
set interfaces ge-0/0/0 description vsrx1_descr_test
set interfaces ge-0/0/0 unit 0 family inet address 192.168.15.66/24
set interfaces ge-0/0/1 unit 0 family inet sampling input
set interfaces ge-0/0/1 unit 0 family inet sampling output
set interfaces ge-0/0/1 unit 0 family inet dhcp
set interfaces ge-0/0/2 unit 0 family inet address 1.1.1.1/30
set interfaces ge-0/0/2 unit 0 family inet address 192.168.99.1/30
And when changes the SALT function like:
interfaces = __salt__['net.cli']('show configuration interfaces | display set', format='xml')['out']['show configuration interfaces | display set']"
to this:
interfaces = __salt__['net.cli']('show configuration interfaces | display set', format='xml')['out']
The output was printed vertically, like this:
s
e
t
i
n
t
e
r
and so on. I broke my head with that one.
Hope this helps. And as always, any correction is welcomed.
Cristian.

Related

Getting 127.0.1.1 instead of 192.168.1.* ip ubuntu python

I am new to python. I want to get the ipaddress of the system. I am connected in LAN. When i use the below code to get the ip, it shows 127.0.1.1 instead of 192.168.1.32. Why it is not showing the LAN ip. Then how can i get my LAN ip. Every tutorials shows this way only. I also checked via connecting with mobile hotspot. Eventhough, it shows the same.
import socket
hostname = socket.gethostname()
IPAddr = socket.gethostbyname(hostname)
print("Your Computer Name is:" + hostname)
print("Your Computer IP Address is:" + IPAddr)
Output:
Your Computer Name is:smackcoders
Your Computer IP Address is:127.0.1.1
Required Output:
Your Computer Name is:smackcoders
Your Computer IP Address is:192.168.1.32
I got this same problem with my raspi.
host_name = socket.gethostname()`
host_addr = socket.gethostbyname(host_name)
and now if i print host_addr, it will print 127.0.1.1.
So i foundthis: https://www.raspberrypi.org/forums/viewtopic.php?t=188615#p1187999
host_addr = socket.gethostbyname(host_name + ".local")
and it worked.
As per the above '/etc/hosts' file content, you have an IP address mapping with '127.0.1.1' to your hostname. This is causing the name resolution to get 127.0.1.1. You can try removing/commenting this line and rerun.
How can I get the IP address of eth0 in Python?
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
print s.getsockname()[0]
This also worked for me:
gethostbyname(gethostname()+'.')
i get the same problem what your are facing. but I get the solution with help of my own idea, And don't worry it is simple to use.
if you familiar to linux you should heard the ifconfig command which return the informations about the network interfaces, and also you should understand about grep command which filter the lines which consist specified words
now just open the terminal and type
ifconfig | grep 255.255.255.0
and hit enter now you will get wlan inet address line alone like below
inet 192.168.43.248 netmask 255.255.255.0 broadcast 192.168.43.255
in your terminal
in your python script just insert
#!/usr/bin/env python
import subprocess
cmd = "ifconfig | grep 255.255.255.0"
inet = subprocess.check_output(cmd, shell = True)
inet = wlan.decode("utf-8")
inet = wlan.split(" ")
inet_addr = inet[inet.index("inet")+1]
print(inet_addr)
this script return your local ip address, this script works for me and I hope this will work for your linux machine
all the best
This solution works for me on Windows. If you're using Linux you could try this line of code instead:
IPAddr = socket.gethostbyname(socket.getfqdn())

scapy dhcp request with custom options

How can I utilize scapy as a dhcp client to request certain DHCP options? Clients will request what they need and a dhcp client should respond accordingly. However, I need to test if certain DHCP options are being sent from a server and these are options my PC won't normally request. These could be options 150, 242, etc.
Can scapy support any of the DHCP options? In the code below, how would I adjust if I wanted to request option 242 or option 150?
ethernet = Ether(dst='ff:ff:ff:ff:ff:ff',src=src_mac_address,type=0x800)
ip = IP(src ='0.0.0.0',dst='255.255.255.255')
udp =UDP (sport=68,dport=67)
bootp = BOOTP(chaddr = hw, ciaddr = '0.0.0.0',xid = 0x01020304,flags= 1)
dhcp = DHCP(options=[("message-type","discover"),"end"])
packet = ethernet / ip / udp / bootp / dhcp
requested_option_1 = 1 # Subnet Mask
requested_option_2 = 6 # Domain Name Servers
requested_option_3 = 15 # Domain Name
requested_option_4 = 44 # NetBIOS (TCP/IP) Name Servers
requested_option_5 = 3 # Routers
requested_option_6 = 33 # Static Routes
requested_option_7 = 150 # TFTP Server address
requested_option_8 = 43 # Vendor Specific Information
bytes_requested_options = struct.pack("8B", requested_option_1,
requested_option_2,
requested_option_3,
requested_option_4,
requested_option_5,
requested_option_6,
requested_option_7,
requested_option_8)
dhcp = DHCP(options=[('message-type', 'discover'),('param_req_list',bytes_requested_options),'end'])
Simply add your options as a integer array, like this:
dhcp = DHCP(options=[('message-type','discover'),
('hostname',hostname),
('param_req_list',
[1,3,6]),
('end')])
Or, in order to use the scapy provided options:
dhcp = DHCP(options=[('message-type','discover'),
('hostname',hostname),
('param_req_list',
[
int(scapy.all.DHCPRevOptions["subnet_mask"][0]),
int(scapy.all.DHCPRevOptions["router"][0]),
int(scapy.all.DHCPRevOptions["name_server"][0])
]),
('end')])

How to query gateway for DNS adress by Python or Perl

The Linux/Windows can get DNS address from the router
I need to write a local dns proxy and how can I get the DNS server addresses like the OS does, are there any Perl or Python modules can do this?
Update
The question should be clear, I need some thing to simulate the interface start and the protocol talking with local router, I can not take a tcpdump before a interface starts. Not sure if there is an sample trace file on internet. Possiblely it's not IP protocol which I am not familiar with.
Update2
As I use local DNS proxy server, the TCP configuration is like showing in picture
If I query Net::DNS::Resolver, I get result: 127.0.0.1 which is not what I needed
Really long, formatted comment supporting Steffen's answer.
TLDR: Steffen is correct (+1 BTW). Net::DNS::Resolver should get you the information you need.
Example:
#!perl
use strict;
use warnings;
use Net::DNS::Resolver;
#configure a resolver object using your OS's current config.
my $resolver = Net::DNS::Resolver->new;
print join "\n", $resolver->nameservers;
Tested on Windows & OS X.
If you are serous in your quest for the rope to hang yourself, the protocol you're asking about is DHCP (Dynamic Host Configuration Protocol).
Using DHCP like your OS does, is not a mere "Query" for DNS servers, but a request for a (new/renewed) lease of an IP Address. The fact that things like Gateway, Time Servers & DNS Servers are included are also important, but secondary. If done incorrectly, you may either screw up the relationship between your OS and the DHCP server or convince your DHCP server that your program is another (false) machine on the network for which it should maintain lease information.
gethostbyname uses the resolver function of the underlying OS library. If you want to have more direct access to the DNS packets use Net::DNS::Resolver.
inspired by Steffen Ullrich
I got the issue resolved, by managed taking a DHCP trace and simulated by Net::DHCP::Packet, fortunately it's simple UDP protocol
You need to findout IP/Mac/GW address before using the script
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use Net::DHCP::Packet;
use Net::DHCP::Constants;
srand();
# creat DHCP Packet
my $discover = Net::DHCP::Packet->new(
Xid => int(rand(0xFFFFFFFF)), # random xid
Flags => 0x0000,
DHO_DHCP_MESSAGE_TYPE() => DHCPREQUEST(),
);
$discover->ciaddr('192.168.1.5');
$discover->chaddr('5cc5d43ca078');
my $handle = IO::Socket::INET->new(
Proto => 'udp',
ReuseAddr => 1,
PeerPort => '67',
LocalPort => '68',
PeerAddr => '192.168.1.1'
) or die "socket: $#";
$handle->send($discover->serialize());
my $newmsg;
if ($handle->recv($newmsg, 1024)) {
my $packet = Net::DHCP::Packet->new($newmsg);
print STDERR $packet->toString();
}
Execution result:
op = BOOTREPLY
htype = HTYPE_ETHER
hlen = 6
hops = 0
xid = eaba416c
secs = 0
flags = 0
ciaddr = 192.168.1.5
yiaddr = 192.168.1.5
siaddr = 0.0.0.0
giaddr = 0.0.0.0
chaddr = 5cc5d43ca078
sname =
file =
Options :
DHO_DHCP_MESSAGE_TYPE(53) = DHCPACK
DHO_SUBNET_MASK(1) = 255.255.255.0
DHO_ROUTERS(3) = 192.168.1.1
DHO_DOMAIN_NAME_SERVERS(6) = 192.168.1.1
DHO_DHCP_SERVER_IDENTIFIER(54) = 192.168.1.1
DHO_DHCP_LEASE_TIME(51) = 86400
DHO_VI_VENDOR_SPECIFIC_INFOMATION(125) = \x00\x00\x00\x00\x14\x02\x06HGW-CT\x0A\x02\x00\x00\x0B\x02\x00U\x0D\x02\x00.
padding [247] = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
We can see
DHO_DOMAIN_NAME_SERVERS(6) = 192.168.1.1
Is the DNS server address

Parsing config settings in python

I am trying to parse a config settings file that I am getting from stdout with an ssh script. I need to get these into key/value pairs. The config settings look something like this:
OUTPUT SETTINGS
show all <==== TRYING TO KEEP THIS LINE FROM BEING PARSED
Active System Configuration <==== TRYING TO KEEP THIS LINE FROM BEING PARSED
# General Information
Unit undefined
Subdivision undefined
Address undefined
Site ID undefined
Device ID 0
# Application FOO Information
FOO BAR AAA 0000
FOO Checkin 0000
# LSD Status Information
LSD not configured/built for vital parameters.
# System Time
Local Time 01-08-14 16:13:50
Time sync Source None
# Last Reset:
A Processor:01-08-14 16:04:31 -- App Select Alarm Not Cleared
B Processor:01-08-14 16:04:26 -- A Processor Initiated Reset
# Active Alarms:
01-08-14 16:04:33 -- App Select Required
# Comm Settings - Port 1
MAC Address 00:00:00:00:01:D3
IP Address 172.168.0.11
SubnetMask 255.255.255.0
DCDC Server Enabled
DCDC Server IP Pool Start 172.168.0.11
DCDC Server IP Pool End 172.168.0.43
DCDC Server Default Gateway 0.0.0.0
# Comm Settings - Port 2
MAC Address 00:00:00:00:01:D3
IP Address 172.168.0.11
SubnetMask 255.255.255.0
DCDC Server Enabled
DCDC Server IP Pool Start 172.168.0.11
DCDC Server IP Pool End 172.168.0.44
DCDC Server Default Gateway 0.0.0.0
Default Gateway 0.0.0.0
# Comm Settings - Routing Table
Route #1 - Disabled
Route #2 - Disabled
Route #3 - Disabled
Route #4 - Disabled
Route #5 - Disabled
Route #6 - Disabled
Route #7 - Disabled
Route #8 - Disabled
# Comm Settings - HTTP Settings
HTTP TCP Port# 1000
Inactivity timeout 60
Trusted Source 1 Status Disabled
Trusted Source 1 IP Addr 0.0.0.0
Trusted Source 1 Net Mask 0.0.0.0
Trusted Source 2 Status Disabled
Trusted Source 2 IP Addr 0.0.0.0
Trusted Source 2 Net Mask 0.0.0.0
# Comm Settings - Count Settings
Count Port 1 Enabled
Count Port 2 Enabled
Inactivity timeout 0
HTTP TCP Port# 23
Trusted Source 1 Status Disabled
Trusted Source 1 IP Addr 0.0.0.0
Trusted Source 1 Net Mask 0.0.0.0
Trusted Source 2 Status Disabled
Trusted Source 2 IP Addr 0.0.0.0
Trusted Source 2 Net Mask 0.0.0.0
# Comm Settings - SSH Settings
SSH Port 1 Enabled
SSH Port 2 Enabled
SSH Inactivity timeout 0
SSH Server Port# 10
# Comm Settings - Diagnostic Port Settings
Bad Rate 57000
Parity None
Data Bits 8
Stop Bits 1
Flow Control Disabled
# Executive Information
PN 050000-000
Ver 8.09Bld0000F
Module KMO-3
Processor A
Copyright FOO(C)2013
TXT AAA0AAA0
#
PN 050000-000
Ver 8.09Bld0000F
Module KMO-3
Processor B
Copyright FOO(C)2013
TXT ABB0ABB0
#
PN 050000-000
Ver 8.09Bld0000F
Module KMO-3
Processor C
Copyright FOO(C)2013
TXT BCC0BCC0
#
HPN 202551-001
Ver 1.1
Module CDU
Processor DF123000
Ref U2
Copyright FOO(C)2013
Datecode 060808
# Boot Information
PN 072000-000
Ver 5.12Bld002
Module FOO-3
Processor A
Copyright FOO(C)2012
TXT DCC0DCC0
#
PN 072000-000
Ver 5.12Bld002
Module FOO-3
Processor B
Copyright FOO(C)2012
TXT EFF0EFF0
#
PN 072000-000
Ver 5.12Bld002
Module FOO-3
Processor C
Copyright FOO(C)2012
TXT EEE0EEE0
# BAR Application
BAR MAP file not loaded
BAR CONFIG file not loaded
# ROK Key Management Configuration
Encrypted CARR Key (No CARR Key Present)
Encrypted CARR TXT (No CARR Key Present)
Pending Encrypted CARR Key (No Future CARR Key Present)
Pending Encrypted CARR TXT (No Future CARR Key Present)
RC2 Key File TXT (No RC2 Key Present)
# Vital Application Information
Name VVDefault App
Index 0
EPT TXT 2578
EPT Checkin 80DC
# Non-Vital Application Information
Name BBDefault App
Index 0
EPT TXT 521D
EPT Checkin 64E0
# ROK Vital Configuration
ROK not configured/build for vital parameters.
# ROK Non-Vital Configuration
ROK not configured/built for non-vital parameters.
# SNMP General Configuration
Build incomplete - ZZ2 module may not present.
SSH> <==== TRYING TO KEEP THIS LINE FROM BEING PARSED
PARSER
# BNF for data
# dataGroups ::= "#" + Optional(restOfLine)
# keyword ::= ( alpha+ )+
# value ::= ( alpha+ )
# configDef ::= Group(keyname + value)
hashmark = Literal('#').suppress()
snmpCommand = Literal("show all").suppress()
sshResidue = Literal("SSH>").suppress()
keyname = Word(alphas,alphanums+'-')
value = Combine(empty + SkipTo(LineEnd()))
GCONF = Keyword("#")
configDef = Group(GCONF + value("name") + \
Dict(OneOrMore(Group(~GCONF + keyname + value))))
configDef = Group(value("name") + \
Dict(OneOrMore(Group(keyname + value))))
configDef.ignore(snmpCommand)
configDef.ignore(sshResidue)
configDef.ignore(hashmark)
# parse the data
ifcdata = OneOrMore(configDef).parseString(data)
for ifc in ifcdata:
print ifc.dump()
Above is what I'm working on using pyparsing, reading through Getting Started with Pyparsing but still getting hung up. Now I have EVERYTHING parsing out, even the "show all" and "Active System Configuration". I am looking at how to omit those and then group the settings based on the "#" symbol, since that is the only similar identifier. I need the parsed data to look something like this:
PARSED DATA
['General Information',['Unit', 'undefined',],['Subdivision', 'undefined',],['Address', 'undefined'],['Site ID','undefined'],['Device ID', '0']]
['Application FOO Information',['FOO BAR', 'AAA 0000'],['FOO Checkin', '0000']]
['LSD Status Information', ['LSD', 'not configured/built for vital parameters.']]
['System Time', ['Local Time', '01-08-14 16:13:50'],['Time sync Source', 'None']]
['Last Reset:', ['A Processor', '01-08-14 16:04:31 -- App Select Alarm Not Cleared']['B Processor', '01-08-14 16:04:26 -- A Processor Initiated Reset']]
['Active Alarms:', ['01-08-14 16:04:33', 'App Select Required']]
.... and so on
I am playing with pyparsing for this because of this post over here. I really like this module. Any help is greatly appreciated. Thanks!
Consider this:
from pyparsing import *
import re
data = ... # data goes here
date_regex = re.compile(r'\d\d-\d\d-\d\d')
time_regex = re.compile(r'\d\d:\d\d:\d\d')
pairs = [{'category': 'General Information',
'kv': Group(Word(alphanums) + Word(alphanums))},
{'category': 'Last Reset:',
'kv': Group(Word(alphas, max=1) + Word(alphas)) + Literal(':').suppress()
+ Group(Regex(date_regex) + Regex(time_regex)
+ Optional(SkipTo(LineEnd())))
}
]
# build list of categories with associated parsing rules
categories = [Word("# ").suppress() + x['category']
+ OneOrMore(Group(x['kv']))
for x in pairs]
# account for thing you don't have specific rules for
categories.append(Word("#").suppress() + Optional(SkipTo(LineEnd())) +
Group(OneOrMore(Combine(Word(alphanums) + SkipTo(LineEnd()))))
)
# OR all the categories together
categories_ored = categories[0]
for c in categories[1:]:
categories_ored |= c
configDef = OneOrMore(categories_ored)
suppress_tokens = ["show all", "SSH>", "Active System Configuration"]
suppresses = [Literal(x).suppress() for x in suppress_tokens]
for s in suppresses:
configDef.ignore(s)
result = configDef.parseString(data)
for e in result:
print(e)
This gives you the following result:
General Information
[['Unit', 'undefined']]
[['Subdivision', 'undefined']]
[['Address', 'undefined']]
[['Site', 'ID']]
[['undefined', 'Device']]
[['ID', '0']]
Application FOO Information
['FOO BAR AAA 0000', 'FOO Checkin 0000']
LSD Status Information
['LSD not configured/built for vital parameters.']
System Time
['Local Time 01-08-14 16:13:50', 'Time sync Source None']
Last Reset:
[['A', 'Processor'], ['01-08-14', '16:04:31', '-- App Select Alarm Not Cleared']]
[['B', 'Processor'], ['01-08-14', '16:04:26', '-- A Processor Initiated Reset']]
Active Alarms:
['01-08-14 16:04:33 -- App Select Required']
Comm Settings - Port 1
['MAC Address 00:00:00:00:01:D3', 'IP Address 172.168.0.11', 'SubnetMask 255.255.255.0', 'DCDC Server Enabled', 'DCDC Server IP Pool Start 172.168.0.11', 'DCDC Server IP Pool End 172.168.0.43', 'DCDC Server Default Gateway 0.0.0.0']
Comm Settings - Port 2
['MAC Address 00:00:00:00:01:D3', 'IP Address 172.168.0.11', 'SubnetMask 255.255.255.0', 'DCDC Server Enabled', 'DCDC Server IP Pool Start 172.168.0.11', 'DCDC Server IP Pool End 172.168.0.44', 'DCDC Server Default Gateway 0.0.0.0', 'Default Gateway 0.0.0.0']
Comm Settings - Routing Table
['Route #1 - Disabled', 'Route #2 - Disabled', 'Route #3 - Disabled', 'Route #4 - Disabled', 'Route #5 - Disabled', 'Route #6 - Disabled', 'Route #7 - Disabled', 'Route #8 - Disabled']
Comm Settings - HTTP Settings
['HTTP TCP Port# 1000', 'Inactivity timeout 60', 'Trusted Source 1 Status Disabled', 'Trusted Source 1 IP Addr 0.0.0.0', 'Trusted Source 1 Net Mask 0.0.0.0', 'Trusted Source 2 Status Disabled', 'Trusted Source 2 IP Addr 0.0.0.0', 'Trusted Source 2 Net Mask 0.0.0.0']
Comm Settings - Count Settings
['Count Port 1 Enabled', 'Count Port 2 Enabled', 'Inactivity timeout 0', 'HTTP TCP Port# 23', 'Trusted Source 1 Status Disabled', 'Trusted Source 1 IP Addr 0.0.0.0', 'Trusted Source 1 Net Mask 0.0.0.0', 'Trusted Source 2 Status Disabled', 'Trusted Source 2 IP Addr 0.0.0.0', 'Trusted Source 2 Net Mask 0.0.0.0']
Comm Settings - SSH Settings
['SSH Port 1 Enabled', 'SSH Port 2 Enabled', 'SSH Inactivity timeout 0', 'SSH Server Port# 10']
Comm Settings - Diagnostic Port Settings
['Bad Rate 57000', 'Parity None', 'Data Bits 8', 'Stop Bits 1', 'Flow Control Disabled']
Executive Information
['PN 050000-000', 'Ver 8.09Bld0000F', 'Module KMO-3', 'Processor A', 'Copyright FOO(C)2013', 'TXT AAA0AAA0']
['PN 050000-000', 'Ver 8.09Bld0000F', 'Module KMO-3', 'Processor B', 'Copyright FOO(C)2013', 'TXT ABB0ABB0']
['PN 050000-000', 'Ver 8.09Bld0000F', 'Module KMO-3', 'Processor C', 'Copyright FOO(C)2013', 'TXT BCC0BCC0']
['HPN 202551-001', 'Ver 1.1', 'Module CDU', 'Processor DF123000', 'Ref U2', 'Copyright FOO(C)2013', 'Datecode 060808']
Boot Information
['PN 072000-000', 'Ver 5.12Bld002', 'Module FOO-3', 'Processor A', 'Copyright FOO(C)2012', 'TXT DCC0DCC0']
['PN 072000-000', 'Ver 5.12Bld002', 'Module FOO-3', 'Processor B', 'Copyright FOO(C)2012', 'TXT EFF0EFF0']
['PN 072000-000', 'Ver 5.12Bld002', 'Module FOO-3', 'Processor C', 'Copyright FOO(C)2012', 'TXT EEE0EEE0']
BAR Application
['BAR MAP file not loaded', 'BAR CONFIG file not loaded']
ROK Key Management Configuration
['Encrypted CARR Key (No CARR Key Present)', 'Encrypted CARR TXT (No CARR Key Present)', 'Pending Encrypted CARR Key (No Future CARR Key Present)', 'Pending Encrypted CARR TXT (No Future CARR Key Present)', 'RC2 Key File TXT (No RC2 Key Present)']
Vital Application Information
['Name VVDefault App', 'Index 0', 'EPT TXT 2578', 'EPT Checkin 80DC']
Non-Vital Application Information
['Name BBDefault App', 'Index 0', 'EPT TXT 521D', 'EPT Checkin 64E0']
ROK Vital Configuration
['ROK not configured/build for vital parameters.']
ROK Non-Vital Configuration
['ROK not configured/built for non-vital parameters.']
SNMP General Configuration
['Build incomplete - ZZ2 module may not present.']
I've implemented parsing for a few key-value pairs in pairs, and added a fallback for the ones that don't have specific parsing rules implemented yet (the categories.append() part). This also successfully keeps the lines you don't want ("SSH>", etc) out of the parsing output. I hope this helps.

Receiving multicast data on specific interface

tcmpdump can view all the multicast traffic to specific group and port on eth2, but my Python program cannot. The Python program, running on Ubuntu 12.04:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Multicast port is 52122
sock.bind(('', 52122))
# Interface eth2 IP is 1.2.3.4, multicast group is 6.7.8.9
mreq = socket.inet_aton('6.7.8.9')+socket.inet_aton('1.2.3.4')
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
print '\nwaiting to receive message'
data, address = sock.recvfrom(1024)
print data
When I use another program to send a multicast packet to eth2, it works and prints the packet. But it fails to see all the current multicast traffic. If I run tcpdump on eth2 on the same port and group as the above program:
sudo tcpdump -i eth2 host 6.7.8.9 and port 52122
it sees both the packets I send from another program AND all the current multicast traffic. It's output looks likes this...
# Packet sent from my other program
09:52:51.952714 IP 1.2.3.4.57940 > 6.7.8.9.52122: UDP, length 19
# Packet send from the outside world
09:52:52.143339 IP 9.9.9.9.39295 > 6.7.8.9.52122: UDP, length 62
Why can't my program see the packets from the outside world? How can I modify it (or something else) to fix this?
Edit:
I should have mentioned, the interface this going over is not eth2 but eth2.200 a VLAN. (The local IP and the tcpdump commands are all run with eth2.200, I just changed that in this question to make it simpler.) Based on this answer that could be the problem?
Edit #2:
netstat -ng when the program is running shows eth2.200 subscribed to 224.0.0.1 and 6.7.8.9`.
tshark -i eth2.200 igmp shows three repeated 1.2.3.4 -> 6.7.8.9 IGMP 46 V2 Membership Report / Join group 6.7.8.9 when the program first starts. When the program process is killed, it shows 1.2.3.4 -> 224.0.0.2 IGMP 46 V2 Leave group 6.7.8.9. There is also an infrequent 1.2.3.1 -> 224.0.0.1 IGMP 60 V2 Membership Query, general, where 1.2.3.1 is 1.2.3.4's gateway.
Not sure if it will help, but the routing table looks like:
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 1.2.5.6 0.0.0.0 UG 0 0 0 eth1
1.2.3.0 0.0.0.0 255.255.255.240 U 0 0 0 eth2.200
Thank you!
Finally! Found this question on ServerFault that addresses the same thing. Basically the kernel was not forwarding on / was filtering out the packets because it thought the sourced address was spoofed.
Changed the settings in /etc/sysctl.conf to match:
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.ip_forward = 1
Rebooted and everything works.

Categories