3

Using telnetlib I pull routing info from my router and want to extract the WAN IP address using a pattern. The output of the telnet session is in a variable with lines separated by \n.

The stuff from the telnet session.

l= tn.read_all()
>>> l
'\r\nip -f inet addr\r\nexit\r\nadmin4asus@RT-AC68U:/tmp/home/root# ip -f inet addr\r\n1: lo: <LOOPBACK,MULTICAST,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN \r\n    inet 127.0.0.1/8 brd 127.255.255.255 scope host lo\r\n2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000\r\n    inet 24.6.29.214/21 brd 24.6.31.255 scope global eth0\r\n7: br0: <BROADCAST,MULTICAST,ALLMULTI,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN \r\n    inet 192.168.11.1/24 brd 192.168.11.255 scope global br0\r\n8: tun21: <POINTOPOINT,MULTICAST,NOARP,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 100\r\n    inet 10.8.0.1 peer 10.8.0.2/32 scope global tun21\r\nadmin4asus@RT-AC68U:/tmp/home/root# exit\r\n'
>>> 

Now my code.

l= tn.read_all()
for line in l.split('\n'):
    match= re.findall( r'([0-9]+(?:\.[0-9]+){3}).*scope global eth0', line)
    if match is not None:
        print('Found ' + line)

I would have expected the one line that matches to print.

Found     inet 24.6.29.214/21 brd 24.6.31.255 scope global eth0

But I get the find everywhere.

Found 
Found ip -f inet addr
Found exit
Found admin4asus@RT-AC68U:/tmp/home/root# ip -f inet addr
Found 1: lo: <LOOPBACK,MULTICAST,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN 
Found     inet 127.0.0.1/8 brd 127.255.255.255 scope host lo
Found 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
Found     inet 24.6.29.214/21 brd 24.6.31.255 scope global eth0
Found 7: br0: <BROADCAST,MULTICAST,ALLMULTI,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN 
Found     inet 192.168.11.1/24 brd 192.168.11.255 scope global br0
Found 8: tun21: <POINTOPOINT,MULTICAST,NOARP,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 100
Found     inet 10.8.0.1 peer 10.8.0.2/32 scope global tun21
Found admin4asus@RT-AC68U:/tmp/home/root# exit
Found 

I can't figure out why my code is failing. If the experts have a better method (with explanation) that would be great.

Edit :

Jan's answer is surely more pythonic, but my lack of knowledge of python makes me prefer vks which is easier to understand for me. I gave both a '^' and will mark vks as preferred (in the sense 'preferred by me').

I ended up using '\r\n' in the 'split' cmd and following code.

def get_asus_wan_ip():
    "Gets WAN IP from ASUS router"

    import telnetlib
    import re

    ASUS_IP=   '192.168.1.1'
    ASUS_USER= 'xxxxxxxx'
    ASUS_PASS= 'yyyyyyyy'
    tn = telnetlib.Telnet(ASUS_IP)

    tn.read_until("login: ")
    tn.write(ASUS_USER + "\n")
    tn.read_until("Password: ")
    tn.write(ASUS_PASS + "\n")
    tn.write("ifconfig eth0\n")
    tn.write("exit\n")
    l= tn.read_all()
    for line in l.split('\r\n'):
        match= re.findall( r'^\s+inet addr:([0-9]+(?:\.[0-9]+){3}).*', line)
        if match:
            break

    wan_ip= match[0]
    return wan_ip
vks
  • 67,027
  • 10
  • 91
  • 124
Gert Gottschalk
  • 1,658
  • 3
  • 25
  • 37
  • 2
    ``re.findall()`` returns a *list* of matches. The list can be empty; it cannot possibly be ``None``. For a single match, you want ``re.search()`` (or re.match()`` if the match has to be at the start of the string). – jasonharper Apr 06 '17 at 05:18
  • Your [**regex works fine**](https://regex101.com/r/rfgo3G/1) (slightly tuned), the `if` construction is the problem. – Jan Apr 06 '17 at 05:23
  • Possible duplicate of [Extract IP address from an html string (python)](http://stackoverflow.com/questions/2890896/extract-ip-address-from-an-html-string-python) – philshem Apr 06 '17 at 13:36

2 Answers2

3
import re
x="""'\r\nip -f inet addr\r\nexit\r\nadmin4asus@RT-AC68U:/tmp/home/root# ip -f inet addr\r\n1: lo: <LOOPBACK,MULTICAST,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN \r\n    inet 127.0.0.1/8 brd 127.255.255.255 scope host lo\r\n2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000\r\n    inet 24.6.29.214/21 brd 24.6.31.255 scope global eth0\r\n7: br0: <BROADCAST,MULTICAST,ALLMULTI,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN \r\n    inet 192.168.11.1/24 brd 192.168.11.255 scope global br0\r\n8: tun21: <POINTOPOINT,MULTICAST,NOARP,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 100\r\n    inet 10.8.0.1 peer 10.8.0.2/32 scope global tun21\r\nadmin4asus@RT-AC68U:/tmp/home/root# exit\r\n'"""
for line in x.split('\n'):
    match= re.findall(r'(?:[0-9]+(?:\.[0-9]+){3}).*scope global eth0', line)
    if match:
        print('Found ' + line)

Output:Found inet 24.6.29.214/21 brd 24.6.31.255 scope global eth0

Problems with your code:

1) re.findall returns list , so it cannot be None it can be empty.So use that in if condition.

2) re.findall returns only groups if there are some.If you want the whole line, make the first group non capturing.

vks
  • 67,027
  • 10
  • 91
  • 124
2

You could vastly shrink your code with a list comprehension:

import re

string = """
1: lo: <LOOPBACK,MULTICAST,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN 
    inet 127.0.0.1/8 brd 127.255.255.255 scope host lo
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
    inet 24.6.29.214/21 brd 24.6.31.255 scope global eth0
7: br0: <BROADCAST,MULTICAST,ALLMULTI,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN 
    inet 192.168.11.1/24 brd 192.168.11.255 scope global br0
8: tun21: <POINTOPOINT,MULTICAST,NOARP,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 100
    inet 10.8.0.1 peer 10.8.0.2/32 scope global tun21
"""

rx = re.compile(r'\b(\d+(?:\.\d+){3})\b.*scope global eth0')
matches = [line
            for line in string.split("\n")
            for match in [rx.search(line)]
            if match]
print(matches)
# ['    inet 24.6.29.214/21 brd 24.6.31.255 scope global eth0']

Or if you prefer filter() and lambda():

matches = list(filter(lambda x: rx.search(x), string.split("\n")))
print(matches)
Jan
  • 42,290
  • 8
  • 54
  • 79