Replace in place a string in file with text from 2nd file - awk

I have two files as follows
config:
which [box-address]
Command ssh user[box2-address]
address:
192.168.0.10
I want to replace in place the [box-address] in "config" with the contents from "address"
I am able to insert the content but overwrite the entire config file each time so instead of
which 192.168.0.10
Command ssh user 192.168.0.20
I end up with
192.168.0.10
as the only thing in the file
What am I doing wrong
awk '/\[box-address\]/{system("cat config");next}1' address > config

You're providing address, not config, as the input to awk. It will never match /\[box-address\]/. Your command is effectively just overwriting config with the content of address.
The following approach should meet your requirements, it reads the content of address into a variable in the BEGIN block and then replaces any instances of [box-address] with it:
awk 'BEGIN{getline l < "address"}/\[box-address\]/{gsub(/\[box-address\]/,l)}1' config
Result:
which 192.168.0.10
Command ssh user[box2-address]

Related

Connect via ssh with a single .bat script to multiple Adresses

I have a environment of 27 Mikrotik Routers and I want to add a user on each one with same credentials.
Normally I had to connect on every Router and click through the GUI to add the user, but now I found a way to use SSH connection via cmd.
I wrote this - which connects on a single Router and performs the Add-User process
ssh admin#10.1.2.3 -password "Passw0rd!" "user add name=customer-support password=#F0ry0u! group=full"
But now I want to make a script which maybe reads in a csv file with the ip adresses of all the routers I want to perform the change on and connect on each Router to execute the command.
Is this possible?
Since SSH is available for MikroTik router, you can indeed read their addresses from a file.
For example, use bash (which you can execute even on Windows through WSL/WSL2 or Git for Windows which includes a MinGW bash)
See for example "Bash Read Comma Separated CSV File on Linux / Unix", here adapted to your case
#!/bin/bash
# Purpose: Read Comma Separated CSV File
# Author: Vivek Gite under GPL v2.0+
# ------------------------------------------
INPUT=data.cvs
OLDIFS=$IFS
IFS=','
[ ! -f $INPUT ] && { echo "$INPUT file not found"; exit 99; }
while read maddress
do
echo "Address : $maddress"
# do your SSH call here
done < $INPUT
IFS=$OLDIFS
But if you really need a bat script, see for instance "Help in writing a batch script to parse CSV file and output a text file".

How can I remove a Host entry from an ssh config file?

The standard format of the file is:
Host example
HostName example.com
Port 2222
Host example2
Hostname two.example.com
Host three.example.com
Port 4444
Knowing the host's short name, I want to remove an entire entry in order to re-add it with new details.
The closest I have got is this, except I need to keep the following Host declaration and the second search term will capture two many terms (like HostName):
sed '/Host example/,/\nHost/d'
With GNU sed:
host="example"
sed 's/^Host/\n&/' file | sed '/^Host '"$host"'$/,/^$/d;/^$/d'
Output:
Host example2
Hostname two.example.com
Host three.example.com
Port 4444
s/^Host/\n&/: Insert a newline before every line that begins with "Host"
/^Host '"$host"'$/,/^$/d: delete all lines matching "Host $host" to next empty line
/^$/d: clean up: delete every empty line
My final solution (which is somewhat OSX orientated) was this. It's largely based on Cyrus' earlier answer.
sed < $SOURCE "/^$/d;s/Host /$NL&/" | sed '/^Host '"$HOST"'$/,/^$/d;' > $SOURCE
This is more resilient to HostName directives which aren't indented.

how can I filter nmap results for multiple strings and output to file?

2I wanted to get a host list of linux servers on my network using nmap, but I'm not sure how to filter the results based on multiple strings. So I'm using something like:
nmap -sT -R --dns-servers 192.168.1.1,192.168.1.2 -p 22 192.168.1.0/24
which gives me the results but of course it's also showing every IP with the closed ports. How can I use logic with awk so that if it finds an IP with a hostname AND finds that the lines below have 'tcp open' it will spit those two lines to an output file?
The typical input to use from nmap would look like:
Interesting ports on server.domain.com (192.168.1.1):
PORT STATE SERVICE
22/tcp open ssh
Interesting ports on server2.domain.com (192.168.1.2):
PORT STATE SERVICE
22/tcp closed ssh
but this would be for every single IP that is scanned, so I'm trying to find a way to have a file with only the hostname and IP "if" it shows as 'tcp open' from the nmap command above. Basically giving you a file with:
server.domain.com (192.168.1.1)
So that I only get the server name and IP if SSH is actually listening on port 22
Based on the sample input and the sample output posted, something like this could work:
awk '/^Interesting/ {
domain = $(NF-1)
ip = substr($NF, 0, length($NF) - 1)
}
$2 == "open" {print domain, ip}' file
This works like this:
If a line starts with "Interesting", then the second to last field is stored as the domain, and the last field (minus the trailing colon) is stored as the ip.
If it finds a line where the second token is "open", then it prints the domain and ip found previously.

redirect input to telnet which are written in some file

I have one file input.txt containing commands which needs to be typed after telnetting to one ip address. How can I do this, without typing all commands one after the another in to telnet session?

How can I write a program (script) to remove obsolete host keys from ~/.ssh/known_hosts?

I use a cluster of about 30 machines that have all recently been reconfigured with new OpenSSH host keys. When I try to log into one, I get this error message (many lines removed for brevity):
# WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! #
The fingerprint for the RSA key sent by the remote host is
52:bb:71:83:7e:d0:e2:66:92:0e:10:78:cf:a6:41:49.
Add correct host key in /home/nr/.ssh/known_hosts to get rid of this message.
Offending key in /home/nr/.ssh/known_hosts:50
I can go remove the offending line manually, in which case I get a different complaint about the IP addresss, which requires removing another line manually, and I have no desire to repeat this exercise 29 times. I would like to write a program to do it. Unfortunately, the line in the .ssh file no longer contains the host name and IP address in clear text, as it did in earlier versions.
So here's my question:
Given a host name and an IP address, how can I write a program to find out which lines of my ~/.ssh/known_hosts store an SSH host key for that host or IP address?
If I can recover this info, I think I can do the rest myself.
Footnote: I would prefer to code in bash/ksh/sh or C or Lua; my Perl and Python are very rusty.
Clarifications:
I don't want to remove the whole file and repopulate it; it contains over a hundred validated keys that I prefer not to re-validate.
Whether I maintain a single master copy or multiple replicas, the problem of scrubbing away a large group of obsolete host keys remains.
Answer
Here's the Lua script I wrote using ssh-keygen -F:
#!/usr/bin/env lua
require 'osutil'
require 'ioutil'
local known = os.getenv 'HOME' .. '/.ssh/known_hosts'
local function lines(name)
local lines = { }
for l in io.lines(name) do
table.insert(lines, l)
end
return lines
end
local function remove_line(host)
local f = io.popen('ssh-keygen -F ' .. os.quote(host))
for l in f:lines() do
local line = l:match '^# Host %S+ found: line (%d+) type %u+$'
if line then
local thelines = lines(known)
table.remove(thelines, assert(tonumber(line)))
table.insert(thelines, '')
io.set_contents(known, table.concat(thelines, '\n'))
return
end
end
io.stderr:write('Host ', host, ' not found in ', known, '\n')
end
for _, host in ipairs(arg) do
local ip = os.capture('ipaddress ' .. host)
remove_line(host)
remove_line(ip)
end
ssh-keygen -R hostname
ssh-keygen -R ipaddress
personally I scrub the IP addresses with a loop and perl, and remove the conflicts by hand.
$!/usr/bin/perl
for (1..30){
`ssh keygen -R 192.168.0.$_`; #note: backticks arent apostrophies
}
If I want to find out on what line the entry for a host lives,
ssh-keygen -F hostname
The same trick works with IP addresses.
touch and edit "clearkey.sh" or what ever name makes you happy.
#! /bin/bash
# $1 is the first argument supplied after calling the script
sed -i "$1d" ~/.ssh/known_hosts
echo "Deleted line $1 from known_hosts file"
Should be able to do "clearkey.sh 3" and it will delete the offending line!
I usually do the following in bash script checkssh to automatically remove the line:
#!/bin/bash
# Path to "known_hosts" file
KH=~/.ssh/known_hosts
# Find the host in the file, showing line number
L=`grep -i -n $1 $KH`
# If line is not found, exit
[[ $? -ne 0 ]] && exit
# Isolate line number
L=`echo $L | cut -f 1 -d :`
sed -i "${L}d" $KH
You can add ssh $1 exit at the end to automatically re-create an entry in the file, if your ssh is configured to do so.
Call it like checkssh <hostname>.
You might like to try the following when script writing:
declare CHANGED_HOST_NAME="host.yourpublic.work";
declare CHANGED_HOST_IP=$(dig +short ${CHANGED_HOST_NAME});
# Remove old IP address if found
[ -z ${CHANGED_HOST_IP} ] || ssh-keygen -R ${CHANGED_HOST_IP};
# Remove old host key
ssh-keygen -R ${CHANGED_HOST_NAME};
# Add new host key
ssh-keyscan ${CHANGED_HOST_NAME} >> $HOME/.ssh/known_hosts;
Big thanks to #Storm Knight (#289844)