diff options
author | Guillaume Mazoyer <gmazoyer@gravitons.in> | 2016-10-15 18:28:36 +0200 |
---|---|---|
committer | Guillaume Mazoyer <gmazoyer@gravitons.in> | 2016-10-15 18:28:36 +0200 |
commit | 7f96173bbd609478a56fe046819c694782241c00 (patch) | |
tree | 915f47dffe9133275932379336962641926ea682 | |
parent | e9818aa8e2599e761893ad26785077b8b152a4c4 (diff) |
Add support for Cisco IOS XR.
Some of the changes might be inaccurate. They have only been tested against
the demo version of a Cisco IOS XRv. Any feedback about real world IOS XR
testing will be appreciated.
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | docs/cisco_iosxr.md | 103 | ||||
-rw-r--r-- | docs/configuration.md | 17 | ||||
-rw-r--r-- | routers/cisco_iosxr.php | 172 | ||||
-rw-r--r-- | routers/router.php | 5 |
5 files changed, 291 insertions, 8 deletions
@@ -18,7 +18,7 @@ execute some commands on routers. The output is sent back to the user. For now this looking glass is quite simple. Here you have some features: * Interface using Javascript and AJAX calls (needs a decent browser) - * Support of BIRD, Cisco, Juniper and Quagga routers + * Support of BIRD, Cisco (IOS and IOS-XR), Juniper and Quagga routers * Support of Telnet and SSH connection to routers using password authentication and SSH keys. * Configurable list of routers diff --git a/docs/cisco_iosxr.md b/docs/cisco_iosxr.md new file mode 100644 index 0000000..de6c51c --- /dev/null +++ b/docs/cisco_iosxr.md @@ -0,0 +1,103 @@ +# Looking Glass: Cisco IOS XR configuration and tips. + +Cisco IOS XR support is rather straightforward thanks to the tasks mecanism. + +## Security and user access + +As security by least privilege is quite efficient, using a restricted user to +execute the commands is advised. + +A root-system access is not necessary, a read-only-tg user is not sufficient +though. So it is better to define a new group of users with access to +specific commands to restrict the looking glass user to what it actually needs +(no more, no less). This is done using **taskgroup** and **usergroup**. + +## Configuration: Task and User Groups + +Log in your Cisco router and type the following commands: + +``` +RP/0/0/CPU0:router#configure +RP/0/0/CPU0:router(config)# taskgroup looking-glass +RP/0/0/CPU0:router(config-tg)#description "Looking Glass required tasks" +RP/0/0/CPU0:router(config-tg)#task read bgp +RP/0/0/CPU0:router(config-tg)#task read basic-services +RP/0/0/CPU0:router(config-tg)#task write basic-services +RP/0/0/CPU0:router(config-tg)#task execute basic-services +RP/0/0/CPU0:router(config-tg)#exit +RP/0/0/CPU0:router(config)#usergroup looking-glass +RP/0/0/CPU0:router(config-ug)#description "Looking Glass users" +RP/0/0/CPU0:router(config-ug)#taskgroup looking-glass +RP/0/0/CPU0:router(config-ug)#exit +RP/0/0/CPU0:router(config)#username <username> +RP/0/0/CPU0:router(config-un)#group looking-glass +RP/0/0/CPU0:router(config-un)# password <password> +RP/0/0/CPU0:router(config-un)#exit +RP/0/0/CPU0:router(config)#commit +RP/0/0/CPU0:router(config)#exit +``` + +Here is the formal configuration for simple copy/paste. +``` +taskgroup looking-glass +taskgroup looking-glass task read bgp +taskgroup looking-glass task read basic-services +taskgroup looking-glass task write basic-services +taskgroup looking-glass task execute basic-services +taskgroup looking-glass description "Looking Glass required tasks" +usergroup looking-glass +usergroup looking-glass taskgroup looking-glass +usergroup looking-glass description "Looking Glass users" +username <username> +username <username> group read-only-tg +username <username> group looking-glass +username <username> secret <password> +``` + +SSH pubkey based authentication is preferred too even if it is pretty boring +to setup with IOS XR. + +The first thing to do is checking the size of the key to use. There are +limitations depending on the hardware. ASR router supports 1024 bit key size +or smaller contrary to what the manual says (supporting up to 2048 bit). + +Supposing that the key is located in `~/.ssh/id_rsa.pub`, a binary base64 file +of the key must be created to be imported inside the router. + +``` +cut -d" " -f2 ~/.ssh/id_rsa.pub | base64 -d >| id_rsa.pub.b64 +``` + +This file can be uploaded on the router in order to be imported. Here is how to do this : + +``` +RP/0/0/CPU0:router#admin +RP/0/0/CPU0:router(admin)#crypto key import authentication rsa username lg id_rsa.pub.b64 +RP/0/0/CPU0:router(admin)#exit +``` + +And to check that the key has been imported properly: + +``` +RP/0/0/CPU0:router#admin +RP/0/0/CPU0:router(admin)#show crypto key authentication rsa username lg +Key label: lg +Type : RSA public key authentication +Size : 1024 +Imported : 00:00:00 UTC Tue Oct 11 2016 +Data : + ... +``` + +And that should be enough. + +## Debug + +Test the SSH connection from the server where the looking glass is installed +and you should see some outputs in your logs. Be careful to potential SSH +connections rate limit if you do heavy testing. + + +## References + + * [1] https://supportforums.cisco.com/document/61306/asr9000xr-using-task-groups-and-understanding-priv-levels-and-authorization diff --git a/docs/configuration.md b/docs/configuration.md index bb1a210..7b7a543 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -117,11 +117,13 @@ interact with it. ```php $config['routers']['router1']['type'] = 'juniper'; ``` -The router type can be Juniper, Cisco, Quagga or BIRD. You can take a look at -the specific documentation for your router. Possible values are: +The router type can be Juniper, Cisco (IOS or IOS-XR), Quagga or BIRD. You can +take a look at the specific documentation for your router. Possible values +are: * juniper **or** junos * cisco **or** ios + * ios-xr **or** iosxr * bird * quagga **or** zebra @@ -132,14 +134,15 @@ with: ```php $config['routers']['router1']['source-interface-id'] = 'lo0'; ``` -for Cisco and Juniper routers (change lo0 with your interface), and with: +for Cisco (except IOS XR) and Juniper routers (change lo0 with your +interface), and with: ```php -$config['routers']['router1']['source-interface-id']['ipv4'] = '192.168.1.1'; $config['routers']['router1']['source-interface-id']['ipv6'] = '2001:db8::1'; +$config['routers']['router1']['source-interface-id']['ipv4'] = '192.168.1.1'; ``` -for BIRD and Quagga routers (use your own IP addresses). Omitting the IPv4 or -the IPv6 version of the source address will result in the router trying to use -the best IP address to contact the destination. +for Cisco IOS XR, BIRD and Quagga routers (use your own IP addresses). +Omitting the IPv6 or the IPv4 version of the source address will result in the +router trying to use the best IP address to contact the destination. After that you need to set the authentication information for the looking glass to be able to log into the router. For this you select a type of diff --git a/routers/cisco_iosxr.php b/routers/cisco_iosxr.php new file mode 100644 index 0000000..8bc6150 --- /dev/null +++ b/routers/cisco_iosxr.php @@ -0,0 +1,172 @@ +<?php + +/* + * Looking Glass - An easy to deploy Looking Glass + * Copyright (C) 2016 Guillaume Mazoyer <gmazoyer@gravitons.in> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +require_once('router.php'); +require_once('includes/utils.php'); + +final class IOSXR extends Router { + protected function build_ping($destination) { + $ping = null; + + if (match_ipv6($destination) || match_ipv4($destination) || + (match_hostname($destination) && !$this->has_source_interface_id())) { + $ping = 'ping '.$destination. ' repeat 10'; + } else if (match_hostname($destination)) { + $hostname = $destination; + $destination = hostname_to_ip_address($hostname, $this->config); + + if (!$destination) { + throw new Exception('No record found for '.$hostname); + } + + if (match_ipv6($destination)) { + $ping = 'ping ipv6 '.(isset($hostname) ? $hostname : $destination). + ' repeat 10'; + } else if (match_ipv4($destination)) { + $ping = 'ping ipv4 '.(isset($hostname) ? $hostname : $destination). + ' repeat 10'; + } else { + throw new Exception('The parameter does not resolve to an IP address.'); + } + } else { + throw new Exception('The parameter is not an IP address or a hostname.'); + } + + if (($ping != null) && $this->has_source_interface_id()) { + if (match_ipv6($destination) && + ($this->get_source_interface_id('ipv6') != null)) { + $ping .= ' source '.$this->get_source_interface_id('ipv6'); + } else if (match_ipv4($destination) && + ($this->get_source_interface_id('ipv4') != null)) { + $ping .= ' source '.$this->get_source_interface_id('ipv4'); + } + } + + return $ping; + } + + protected function build_traceroute($destination) { + $traceroute = null; + + if (match_ipv6($destination) || match_ipv4($destination) || + (match_hostname($destination) && !$this->has_source_interface_id())) { + $traceroute = 'traceroute '.$destination; + } else if (match_hostname($destination)) { + $hostname = $destination; + $destination = hostname_to_ip_address($hostname); + + if (!$destination) { + throw new Exception('No record found for '.$hostname); + } + + if (match_ipv6($destination)) { + $traceroute = 'traceroute ipv6 '.(isset($hostname) ? $hostname : $destination); + } else if (match_ipv4($destination)) { + $traceroute = 'traceroute ipv4 '.(isset($hostname) ? $hostname : $destination); + } else { + throw new Exception('The parameter does not resolve to an IP address.'); + } + } else { + throw new Exception('The parameter is not an IP address or a hostname.'); + } + + if (($traceroute != null) && $this->has_source_interface_id()) { + if (match_ipv6($destination) && + ($this->get_source_interface_id('ipv6') != null)) { + $traceroute .= ' source '.$this->get_source_interface_id('ipv6'); + } else if (match_ipv4($destination) && + ($this->get_source_interface_id('ipv4') != null)) { + $traceroute .= ' source '.$this->get_source_interface_id('ipv4'); + } + } + + return $traceroute; + } + + protected function build_commands($command, $parameter) { + $commands = array(); + + switch ($command) { + case 'bgp': + if (match_ipv6($parameter, false)) { + $commands[] = 'show bgp ipv6 unicast '.$parameter; + } else if (match_ipv4($parameter, false)) { + $commands[] = 'show bgp ipv4 unicast '.$parameter; + } else { + throw new Exception('The parameter is not an IP address.'); + } + break; + + case 'as-path-regex': + if (match_aspath_regex($parameter)) { + if (!$this->config['disable_ipv6']) { + $commands[] = 'show bgp ipv6 unicast regexp "'.$parameter. + '"'; + } + if (!$this->config['disable_ipv4']) { + $commands[] = 'show bgp ipv4 unicast regexp "'.$parameter. + '"'; + } + } else { + throw new Exception('The parameter is not an AS-Path regular expression.'); + } + break; + + case 'as': + if (match_as($parameter)) { + if (!$this->config['disable_ipv6']) { + $commands[] = 'show bgp ipv6 unicast regexp "^'.$parameter. + '_"'; + } + if (!$this->config['disable_ipv4']) { + $commands[] = 'show bgp ipv4 unicast regexp "^'.$parameter. + '_"'; + } + } else { + throw new Exception('The parameter is not an AS number.'); + } + break; + + case 'ping': + try { + $commands[] = $this->build_ping($parameter); + } catch (Exception $e) { + throw $e; + } + break; + + case 'traceroute': + try { + $commands[] = $this->build_traceroute($parameter); + } catch (Exception $e) { + throw $e; + } + break; + + default: + throw new Exception('Command not supported.'); + } + + return $commands; + } +} + +// End of cisco_iosxr.php diff --git a/routers/router.php b/routers/router.php index 26a9226..8bf771b 100644 --- a/routers/router.php +++ b/routers/router.php @@ -23,6 +23,7 @@ require_once('includes/config.defaults.php'); require_once('config.php'); require_once('bird.php'); require_once('cisco.php'); +require_once('cisco_iosxr.php'); require_once('juniper.php'); require_once('quagga.php'); require_once('includes/utils.php'); @@ -170,6 +171,10 @@ abstract class Router { case 'ios': return new Cisco($config, $router_config, $id, $requester); + case 'ios-xr': + case 'iosxr': + return new IOSXR($config, $router_config, $id, $requester); + case 'juniper': case 'junos': return new Juniper($config, $router_config, $id, $requester); |