1
0
Fork 1
mirror of https://github.com/thatmattlove/hyperglass.git synced 2026-01-17 08:48:05 +00:00

fixed issue with IPv6 BGP Route lookups

This commit is contained in:
checktheroads 2019-05-10 14:10:32 -07:00
parent 04e94462fe
commit eb947a7c17
6 changed files with 107 additions and 39 deletions

View file

@ -0,0 +1,58 @@
More than likely, you'll want to "lock down" what commands can be executed with the credentials you've provided in `hyperglass/hyperglass/config/devices.toml`. It is **strongly** recommended to use a low privilege read only account and not your full administrator account. Even though Hyperglass is coded to only run certain commands to begin with, you're more than likely still exposing the server Hyperglass runs on to the internet, and on that server is a plain text file with your router's credentials in it. Take precautions.
# Creating Restricted Accounts
## Cisco IOS
On Cisco IOS, **parser views** are the recommended tool to restrict access. Basic instructions for configuring Cisco IOS parser views for the default enabled query types are below:
```
parser view hyperglass
secret <secret>
commands exec include all terminal width
commands exec include all terminal length
commands exec include all traceroute
commands exec include all ping
commands exec include all show bgp
!
username hyperglass privilege 15 view hyperglass secret <secret>
```
!!! info "Terminal"
The `terminal length` and `terminal width` commands are required by Netmiko for session handling. If you remove these, Hyperglass will not work.
## Cisco IOS-XR
On Cisco IOS-XR, **taskgroups** are the recommended tool to restrict access. Basic instructoins for configuring Cisco IOS-XR taskgroups for the default enabled query types are below:
```
taskgroup hyperglass
task read bgp
!
usergroup hyperglass
taskgroup hyperglass
!
username hyperglass
group hyperglass
group operator
secret <secret>
```
!!! warning "IOS-XR"
I have not yet figured out a way to enable all the extended options for `ping` and `traceroute` (source IP, count, etc.) without adding the `group operator` statement to the taskgroup. If anyone knows of a way to do this, I welcome a docs PR.
## Juniper
On JunOS, **system login classes** are the recommended tool to restrict access. Basic instructoins for configuring Juniper JunOS login classes for the default enabled query types are below:
```
edit system login class hyperglass
set permissions floppy
set allow-commands-regexp [ "show route protocol bgp" ping traceroute "show route protocol bgp table inet.0" "show route protocol bgp table inet6.0" "ping inet" "ping inet6" "traceroute inet" "traceroute inet6" ]
top
set system login user hyperglass class hyperglass authentication plain-text-password
```

View file

@ -68,7 +68,10 @@ cache = Cache(
def clearCache(): def clearCache():
"""Function to clear the Flask-Caching cache""" """Function to clear the Flask-Caching cache"""
with app.app_context(): with app.app_context():
cache.clear() try:
cache.clear()
except:
raise
# Main / Flask route where html is rendered via Jinja2 # Main / Flask route where html is rendered via Jinja2

View file

@ -21,6 +21,7 @@ routers_list = devices["router"]
# Also handles input validation & error handling # Also handles input validation & error handling
def cmd_construct(router, cmd, ipprefix): def cmd_construct(router, cmd, ipprefix):
inputParams = router, cmd, ipprefix inputParams = router, cmd, ipprefix
log.warning(*inputParams)
try: try:
# Loop through routers config file, match input router with configured routers, set variables # Loop through routers config file, match input router with configured routers, set variables
for r in routers_list: for r in routers_list:
@ -56,7 +57,9 @@ def cmd_construct(router, cmd, ipprefix):
i=ipprefix i=ipprefix
) )
code = 200 code = 200
log.info(msg, code, router, type, command) log.warning(
msg, code, router, type, command
)
return (msg, code, router, type, command) return (msg, code, router, type, command)
# Extended Communities, 32 bit format # Extended Communities, 32 bit format
elif re.match("^[0-9]{1,10}$", ipprefix): elif re.match("^[0-9]{1,10}$", ipprefix):
@ -67,7 +70,9 @@ def cmd_construct(router, cmd, ipprefix):
i=ipprefix i=ipprefix
) )
code = 200 code = 200
log.info(msg, code, router, type, command) log.warning(
msg, code, router, type, command
)
return (msg, code, router, type, command) return (msg, code, router, type, command)
# RFC 8092 Large Community Support # RFC 8092 Large Community Support
elif re.match( elif re.match(
@ -81,7 +86,9 @@ def cmd_construct(router, cmd, ipprefix):
i=ipprefix i=ipprefix
) )
code = 200 code = 200
log.info(msg, code, router, type, command) log.warning(
msg, code, router, type, command
)
return (msg, code, router, type, command) return (msg, code, router, type, command)
else: else:
msg = "{i} is an invalid BGP Community Format.".format( msg = "{i} is an invalid BGP Community Format.".format(
@ -100,7 +107,9 @@ def cmd_construct(router, cmd, ipprefix):
i=ipprefix i=ipprefix
) )
code = 200 code = 200
log.info(msg, code, router, type, command) log.warning(
msg, code, router, type, command
)
return (msg, code, router, type, command) return (msg, code, router, type, command)
else: else:
msg = "{i} is an invalid AS_PATH regex.".format( msg = "{i} is an invalid AS_PATH regex.".format(
@ -121,7 +130,7 @@ def cmd_construct(router, cmd, ipprefix):
i=ipprefix i=ipprefix
) )
code = 200 code = 200
log.info( log.warning(
msg, code, router, type, command msg, code, router, type, command
) )
return ( return (
@ -132,31 +141,25 @@ def cmd_construct(router, cmd, ipprefix):
command, command,
) )
# Use netaddr library to verify if input is a valid IPv6 address or prefix # Use netaddr library to verify if input is a valid IPv6 address or prefix
elif IPNetwork(ipprefix).ip.version == 6: elif IPNetwork(ipprefix).ip.version == 6:
for a, c in ipv6_commands.items(): for a, c in ipv6_commands.items():
if a == cmd: if a == cmd:
command = c.format( command = c.format(target=ipprefix)
target=ipprefix msg = "{i} is a valid IPv6 Adddress.".format(
) i=ipprefix
msg = "{i} is a valid IPv6 Adddress.".format( )
i=ipprefix code = 200
) log.warning(
code = 200 msg, code, router, type, command
log.info( )
msg, return (
code, msg,
router, code,
type, router,
command, type,
) command,
return ( )
msg, # Exception from netaddr library will return a user-facing error
code,
router,
type,
command,
)
# Exception from netaddr library will return a user-facing error
except: except:
msg = "{i} is an invalid IP Address.".format( msg = "{i} is an invalid IP Address.".format(
i=ipprefix i=ipprefix
@ -178,7 +181,7 @@ def cmd_construct(router, cmd, ipprefix):
i=ipprefix i=ipprefix
) )
code = 200 code = 200
log.info( log.warning(
msg, code, router, type, command msg, code, router, type, command
) )
return ( return (
@ -199,7 +202,7 @@ def cmd_construct(router, cmd, ipprefix):
i=ipprefix i=ipprefix
) )
code = 200 code = 200
log.info( log.warning(
msg, code, router, type, command msg, code, router, type, command
) )
return ( return (

View file

@ -26,6 +26,7 @@ general_error = "Error connecting to device."
def cmd_execute(lg_data): def cmd_execute(lg_data):
log.warning(lg_data)
# Check POST data from JS, if location matches a configured router's # Check POST data from JS, if location matches a configured router's
# location, use the router's configured IP address to connect # location, use the router's configured IP address to connect
for r in routers_list: for r in routers_list:
@ -47,6 +48,7 @@ def cmd_execute(lg_data):
log.error(msg, code, lg_data) log.error(msg, code, lg_data)
return (msg, code, lg_data) return (msg, code, lg_data)
# Send "clean" request to cmd_construct to build the command that will be sent to the router # Send "clean" request to cmd_construct to build the command that will be sent to the router
print(lg_router_address)
msg, status, router, type, command = cmd_construct( msg, status, router, type, command = cmd_construct(
lg_router_address, lg_data["cmd"], lg_data["ipprefix"] lg_router_address, lg_data["cmd"], lg_data["ipprefix"]
) )

View file

@ -1,6 +1,9 @@
import os import os
import sys import sys
import app import app
import logging
log = logging.getLogger(__name__)
def clearcache(): def clearcache():
@ -11,10 +14,8 @@ def clearcache():
for arg in sys.argv: for arg in sys.argv:
try: if arg == "clearcache":
if arg == "clearcache": try:
clearcache() clearcache()
print("Successfully cleared cache.") except:
except: raise
print("Failed to clear cache.")
raise

View file

@ -85,6 +85,7 @@
<div class="control has-icons-left"> <div class="control has-icons-left">
<div class="select is-medium is-rounded"> <div class="select is-medium is-rounded">
<select id="network" name="network"> <select id="network" name="network">
<!-- <option value="" disabled></option> -->
{% for net in device_networks %} {% for net in device_networks %}
<option value="{{ net }}">AS{{ net }}</option> <option value="{{ net }}">AS{{ net }}</option>
{% endfor %} {% endfor %}