Expect Script: Parse Specific Info From Cisco CLI - parsing

I'm new to Expect scripting, and trying to parse Cisco router ACL output.
I'm specifically trying to parse IP addresses between the first 2 remark lines. Any help greatly appreciated.
Here's one of my random attempts. It parses IP addresses from the ACL, but doesn't stop at the 2nd remark line:
send "show run | section ip access-list extended OUTSIDE\r\n"
set ip {}
expect {
"remark ##### DENIED HOSTS #####\r\n" {
expect -re {(\d+\.\d+\.\d+\.\d+)} {
set ip "${ip}$expect_out(0,string)"
puts $ip
set ip {}
exp_continue
}
}
}
Not only does the script not stop at the 2nd remark line like I want it to, but it doesn't seem to have an exit point and waits for Expect to timeout.
Random sample ACL for reference:
ip access-list extended OUTSIDE
remark ##### DENIED HOSTS #####
deny ip host 2.2.2.2 any
deny ip host 9.9.9.9 any
deny ip host 8.7.6.5 any
deny ip host 5.6.7.8 any
deny ip host 5.5.5.5 any
deny ip host 4.4.4.4 any
deny ip host 3.3.3.3 any
remark ########################
permit tcp any any eq 22
deny ip any any
permit ip host 2.3.5.1 any
I basically want to parse addresses from 2.2.2.2 to 3.3.3.3, but then exit once the script reaches the 2nd remark line.

With exp_continue, it is always better to add the case where we want to terminate from expect. So that, if the exit case arrived, we can terminate from the expect. Else, obviously timeout will happen.
E.g.
expect{
“p” {send “\r\r\r”; exp_continue}
“+” {incr foo; exp_continue}
“i” {puts "test"; exp_continue}
“quit” exit
}
As you can see, if the word 'quit' comes, then it will be exited.
Lets come to your question. You need to exit from expect when the word
'remark ########################' arrives. But, if we code like,
expect {
"remark ##### DENIED HOSTS #####\r\n" {
expect {
"remark ########################" {exit}
-re {(\d+\.\d+\.\d+\.\d+)} {
set ip "${ip}$expect_out(0,string)"
puts "-->$ip"
set ip {}
exp_continue
}
}
}
}
Program will terminate the expect while the ip parsing is in progress at the middle of anything.
Instead of doing this way, you can better get the whole output and try to parse it as a separate variable, to avoid overhead within expect.
send "show run | section ip access-list extended OUTSIDE\r\n"
expect {
-re {deny\s+ip\s+host\s+(.*)remark} { puts "match found" }
timeout {puts "timeout happened"}
}
Now we have the match and it will be available in the variable expect_out(1,string).
Then we can do regexp in the variable and parse the ip address.
puts [ regexp -inline -all {\d.\d.\d.\d} $expect_out(1,string) ]
You can try one more way as below. Instead of doing regular expression at the expect, you can simply get the whole output and then do the regexp as below.
send "sh run | section ip access-list extended OUTSIDE\r"
#Assuming your router's hostname is `Router`
expect "Router#"
#output will hold the command output.
set output expect_out(buffer)
puts $output
set ip_list [regexp -inline -all {\d.\d.\d.\d} $output]
foreach ip $ip_list {
puts $ip
}

Thanks to Dinesh!!!
Reposting the final working code (or a mix of Dinesh-provided code) here so it's not lost in all the text above (and so I can format more easily than in the comment section).
send "show run | section ip access-list extended OUTSIDE\n"
expect -re {remark(.*)remark}
set output $expect_out(buffer)
#puts $output
puts "\r"
set ip_list [regexp -inline -all {\d.\d.\d.\d} $output]
foreach ip $ip_list {
puts $ip
}
I commented out the 1st puts line, but left it there to use when testing to see what's actually being stored in $output.
Here's the ACL that was parsed from the router CLI:
ip access-list extended OUTSIDE
remark ##### DENIED HOSTS #####
deny ip host 2.2.2.2 any
deny ip host 9.9.9.9 any
deny ip host 8.7.6.5 any
deny ip host 5.6.7.8 any
deny ip host 5.5.5.5 any
deny ip host 4.4.4.4 any
deny ip host 3.3.3.3 any
remark ########################
permit tcp any any eq 22
deny ip host 82.28.82.28 any
permit ip host 2.3.5.1 any
I know, it's a completely convoluted ACL, but it worked great for testing.
Here's Expect script output after parsing the ACL:
2.2.2.2
9.9.9.9
8.7.6.5
5.6.7.8
5.5.5.5
4.4.4.4
3.3.3.3
Any / all IP addresses after the 2nd ACL remark line are ignored as desired!
Thanks Dinesh!

why dont you use perl with Net::Telnet::Cisco ?
https://metacpan.org/pod/Net::Telnet::Cisco

Related

docked flask / waitress.serve not visible in local network

I have my server running under docker and start it with the command serve(app, listen='*:5000').
I can:
access it in container under both 127.0.0.1:5000 amd localhost:5000
access it from outside the container under localhost:5000
I cannot:
access it from outside container under '127.0.0.1:5000'
access it from local network using local ip (and this is what matters the most to me)
I was trying to pass the local address into the serve command but it throws error saying that the address cannot be accessed. Also tried the host='0.0.0.0'. Did not help.
Would anyone know how to make it visible outside of my machine?
ok so i found a solutions that seems to do the trick. the problem was wsl.
at github wsl repo there is a script that sets a bridge.
below i post the code so it does not perish.
credit to edwindijas
$found = $remoteport -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';
if( $found ){
$remoteport = $matches[0];
} else{
echo "The Script Exited, the ip address of WSL 2 cannot be found";
exit;
}
#[Ports]
#All the ports you want to forward separated by coma
$ports=#(80,443,10000,3000,5000);
#[Static ip]
#You can change the addr to your ip config to listen to a specific address
$addr='0.0.0.0';
$ports_a = $ports -join ",";
#Remove Firewall Exception Rules
iex "Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' ";
#adding Exception Rules for inbound and outbound Rules
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $ports_a -Action Allow -Protocol TCP";
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort $ports_a -Action Allow -Protocol TCP";
for( $i = 0; $i -lt $ports.length; $i++ ){
$port = $ports[$i];
iex "netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr";
iex "netsh interface portproxy add v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$remoteport";
}
If you have not already done so, try exposing port 5000.
This can be done by adding
EXPOSE 5000
to your Dockerfile. You will also need to have host='0.0.0.0' in your serve in order to be able to access your page from the local network.

NGINX whitelist internal docker IP

I have a server that runs 2 docker containers, a Node.js API container, and an NGINX-RTMP container. The server itself also uses NGINX as a reverse proxy to sort traffic between these two containers based on port.
The NGINX-RTMP server accesses the API server via it's network alias like so:
on_publish http://api-server:3000/authorize
Which works great to communicate container-to-container. I can also go the other way by using urls like
http://nginx-server:8080/some-endpoint
Now I have a route on the NGINX server that I would like to restrict to just local traffic (i.e. only the API server should be able to hit this location). Now normally I can do this with a simple
# nginx conf file
location /restricted {
allow 127.0.0.1;
deny all;
}
What I would like to do is something like this:
# nginx conf file
location /restricted {
allow api-server;
deny all;
}
But I need to use the actual IP of the container. Now I can get the IP of the container by inspecting it, and I see the IP is 172.17.0.1. However when I look at other instances of this server I see some servers are 172.18.0.1 and 17.14.0.2 so it's not 100% consistent across servers. Now I could just write out all 256 variations of 172.*.0.0/24 but I imagine there must be a 'proper' way to wildcard this in nginx, or even a better way of specifying the container IP in my NGINX conf file. The only information I have found so far is to modify the type of network I'm using for my containers, but I don't want to do that.
How do I properly handle this?
# nginx conf file
location /restricted {
allow 172.*.0.0/24;
deny all;
}
I might have solved this one on my own actually.
Originally I thought I could 172.0.0.1/8 the block to allow all the IPs I thought possible for the local network, but this is wrong.
After reading this article: https://www.arin.net/reference/research/statistics/address_filters/ (archive mirror)
According to standards set forth in Internet Engineering Task Force (IETF) document RFC-1918 , the following IPv4 address ranges are reserved by the IANA for private internets
10.0.0.0/8 IP addresses: 10.0.0.0 – 10.255.255.255
172.16.0.0/12 IP addresses: 172.16.0.0 – 172.31.255.255
192.168.0.0/16 IP addresses: 192.168.0.0 – 192.168.255.255
Notice that the 172 net is a /12 and not /8.
Which is explained as
In August 2012, ARIN began allocating “172” address space to internet service, wireless, and content providers.
So I believe the correct method is:
# nginx conf file
location /restricted {
allow 172.16.0.0/12;
deny all;
}

restrict SSH connection to specific URL/domain name

I have a server with 2 domain names (let's say domain1.com and domain2.com).
I can SSH into the server by ssh user#domain1.com and ssh user#domain2.com. I would like to be able to only allow ssh user#domain1.com and disable SSH acces to domain2.com.
Is that possible?
It does not seem possible to allow SSH connection only to specific domain name. The domain name is resolved by the DNS and there is no way for the SSH server to know which domain you are using. See also this answer to the same question.
One thing you might try to do is to configure a firewall (for example iptable) to drop connection to domain2.com on port 22.
A similar problem was discussed here, where they were trying to block a domain in iptables so that visitor could not access the http server using it.
Adjusting the iptables rule to your case ( and assuming that your ssh server is running on port 22) I would try this:
iptables -I INPUT -p tcp --dport 22 -m string --string "Host: domain2.com" --algo bm -j DROP
UPDATE:
As Dusan Bajic commented the rule above would only work for http traffic because it take advantage of the http header fields. This would not work for ssh traffic.

How to change Freeradius3 default port(auth1812 & Account1813)

I am using freeradius3.0.4. I need to change the default port(1812,1813) to 18120 and 18130. I don't know where it is. Please help! there is no port setting in the main conf.
Change the port under /etc/service.
This is what I get on freeRADIUS Version 3.0.16:
$ sudo freeradius -X -i 0.0.0.0 -p 1850
radiusd: #### Opening IP addresses and Ports ####
Listening on auth address * port 1850
Listening on acct address * port 1851
Listening on proxy address * port 56033
Ready to process requests
From man freeradius:
-p port
Defines which port is used for receiving authentication packets. Accounting packets are received on "port + 1".
When this command-line option is given, all "listen" sections in radiusd.conf are ignored.
This option MUST be used in conjunction with "-i".
So if you'd like to make the changes permanent, it seems that you need to add a "listen" section to your configuration file with the appropriate parameters (didn't have time to look up the exact syntax).
Also note the constraint that the accounting port is always going to be the authentication port plus one. If you really must modify this behavior on freeRADIUS you might have to change the source code and build your own version.
The port number is defined in /etc/freeradius/3.0/sites-enabled/default:
server default {
listen {
type = auth
ipaddr = *
port = 0
limit {
max_connections = 16
lifetime = 0
idle_timeout = 30
}
}
listen {
ipaddr = *
port = 0
type = acct
limit {
}
}
... more configuration
}
As you can see the configured port is 0. This just means it'll use the FreeRADIUS default port which is 1812/1813 (auth/acct).
If you want to change these port numbers, change them in the above file and run systemctl restart freeradius
If you want to run 2 RADIUS sessions in parallel you'd have to cp -rp /etc/freeradius /etc/freeradius2 and start a second RADIUS process with freeradius -X -d /etc/freeradius2
Hope I could help, I also had this issue
Edits:
0 means that it will use the port defined in /etc/services (by default is 1812)
Instead of freeradius -X -c ... use freeradius -X -d ... to use a custom directory
Use cp -rp ... because otherwise the permissions would change and FreeRADIUS wouldn't work anymore

scp with port number specified

I'm trying to scp a file from a remote server to my local machine. Only port 80 is accessible.
I tried:
scp -p 80 username#www.myserver.com:/root/file.txt .
but got this error: cp: 80: No such file or directory
How do I specify the port number in a scp command?
Unlike ssh, scp uses the uppercase P switch to set the port instead of the lowercase p:
scp -P 80 ... # Use port 80 to bypass the firewall, instead of the scp default
The lowercase p switch is used with scp for the preservation of times and modes.
Here is an excerpt from scp's man page with all of the details concerning the two switches, as well as an explanation of why uppercase P was chosen for scp:
-P port   Specifies the port to connect to on the remote host. Note that this option is written with a capital 'P', because -p is already
reserved for preserving the times and modes of the file in rcp(1).
-p           Preserves modification times, access times, and modes from the original file.
Bonus Tip: How can I determine the port being used by the/an SSH daemon to accept SSH connections?
This question can be answered by using the netstat utility, as follows:
sudo netstat -tnlp | grep sshd
Or, using the far more readable word based netstat option names:
sudo netstat --tcp --numeric-ports --listening --program | grep sshd
The output you will see, assuming your ssh daemon is configured with default values its listening ports, is shown below (with a little trimming of the whitespace in between columns, in order to get the entire table to be visible without having to scroll):
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State ID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 888/sshd: /usr/sbin
tcp6 0 0 :::22 :::* LISTEN 888/sshd: /usr/sbin
Important Note
For the above examples, sudo was used to run netstat with administrator privs, in order to be able to see all of the Program Names. If you run netstat as a regular user (i.e., without sudo and assuming you don't have admin rights granted to you, via some other method), you will only see program names shown for sockets that have your UID as the owner. The Program Names for sockets belonging to other users will not be shown (i.e., will be hidden and a placeholder hyphen will be displayed, instead):
Proto Recv-Q Send-Q Local Address Foreign Address State ID/Program name
tcp 0 0 127.0.0.1:46371 0.0.0.0:* LISTEN 4489/code
...
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
...
Update and aside to address one of the (heavily upvoted) comments:
With regard to Abdull's comment about scp option order, what he suggests:
scp -r some_directory -P 80 ...
..., intersperses options and parameters, since the -r switch takes no additional arguments and some_directory is treated as the first parameter to the command, making -P and all subsequent command line arguments look like additional parameters to the command (i.e., hyphen prefixed arguments are no longer considered as switches).
getopt(1) clearly defines that parameters must come after options (i.e., switches) and not be interspersed with them, willy-nilly:
The parameters getopt is called with can be divided into two parts: options which modify the way getopt will do the parsing (the options and the optstring in the SYNOPSIS), and the parameters which are to be parsed (parameters in the SYNOPSIS). The second part will start at
the first non-option parameter that is not an option argument, or after the first occurrence of '--'. If no '-o' or '--options' option is found in the first part, the first parameter of the second part is used as the short options string.
Since the -r command line option takes no further arguments, some_directory is "the first non-option parameter that is not an option argument." Therefore, as clearly spelled out in the getopt(1) man page, all succeeding command line arguments that follow it (i.e., -P 80 ...) are assumed to be non-options (and non-option arguments).
So, in effect, this is how getopt(1) sees the example presented with the end of the options and the beginning of the parameters demarcated by gray text:
scp -r some_directory -P 80 ...
This has nothing to do with scp behavior and everything to do with how POSIX standard applications parse command line options using the getopt(3) set of C functions.
For more details with regard to command line ordering and processing, please read the getopt(1) manpage using:
man 1 getopt
One additional hint. Place the '-P' option after the scp command, no matter whether the machine you are ssh-ing into is the second one (aka destination). Example:
scp -P 2222 /absolute_path/source-folder/some-file user#example.com:/absolute_path/destination-folder
You know what's cooler than -P? nothing
If you use this server more than a few times, setup/create a ~/.ssh/config file with an entry like:
Host www.myserver.com
Port 80
or
Host myserver myserver80 short any.name.u.want yes_anything well-within-reason
HostName www.myserver.com
Port 80
User username
Then you can use:
scp username#www.myserver.com:/root/file.txt .
or
scp short:/root/file.txt .
You can use anything on the "Host" line with ssh, scp, rsync, git & more
There are MANY configuration option that you can use in config files, see:
man ssh_config
I'm using different ports then standard and copy files between files like this:
scp -P 1234 user#[ip address or host name]:/var/www/mywebsite/dumps/* /var/www/myNewPathOnCurrentLocalMachine
This is only for occasional use, if it repeats itself based on a schedule you should use rsync and cron job to do it.
for use another port on scp command use capital P like this
scp -P port-number source-file/directory user#domain:/destination
ya ali
This can be achived by specifying port via the -P switch:
scp -i ~/keys/yourkey -P2222 file ubuntu#host:/directory/
Port can be specified using the scp protocol path: scp://[user#]host[:port][/path]
From man scp:
The source and target may be specified as a local pathname, a remote host with optional path in the form [user#]host:[path], or a URI in the form
scp://[user#]host[:port][/path]. Local file names can be made explicit using absolute or relative pathnames to avoid scp treating file names containing `:'
as host specifiers.
Examples:
scp local/filename scp://user#acme.com:22222/path/to/filename
scp scp://userA#foo.com:22222/path/to/filename scp://userB#bar.com:33333/path/to/filename
Note, if your path is from root, you will need to have two /s in your path. For example,
scp local/filename scp://user#acme.com:22222//root/path/to/filename
scp help tells us that port is specified by uppercase P.
~$ scp
usage: scp [-12346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]
[-l limit] [-o ssh_option] [-P port] [-S program]
[[user#]host1:]file1 ... [[user#]host2:]file2
Hope this helps.
scp -P 22 -r DIR huezo#192.168.1.100:/home/huezo
scp -P PORT -r DIR USER#IP:/DIR
if you need copy local file to server (specify port )
scp -P 3838 /the/source/file username#server.com:/destination/file
To backup all files in all directories to a remote Synology NAS using a different remote port:
scp -P 10022 -r /media/data/somedata/* user#192.168.1.x:/var/services/homes/user/directory/
Copying file to host:
scp SourceFile remoteuser#remotehost:/directory/TargetFile
Copying file from host:
scp user#host:/directory/SourceFile TargetFile
Copying directory recursively from host:
scp -r user#host:/directory/SourceFolder TargetFolder
NOTE: If the host is using a port other than port 22, you can specify it with the -P option:
scp -P 2222 user#host:/directory/SourceFile TargetFile
Hope this will help someone looking for a perfect answer
Copying a folder or file from a server with a port defined to another server or local machine
Go to a directory where you have admin rights preferably your home directory on the machine where you want to copy files to
Write the command below
scp -r -P port user#IP_address:/home/file/pathDirectory .
**Note:** The last . on the command directs it to copy everything in that folder to your directory of preference
There are many answers, but you should just be able to keep it simple. Make sure you know what port SSH is listening on, and define it. Here is what I just used to replicate your problem.
scp -P 12222 file.7z user#193.168.X.X:/home/user/Downloads
It worked out well.

Resources