Find IP address and validate which subnet it is in - bash

We have 3 buildings and I would like to identify the IP that a computer has and then identify which subnet it is in using a series of if/else statements.
For example:
Building 1 = 192.168.1.1 /24
Building 2 = 192.168.2.1 /24
Building 3 = 192.168.3.1 /24
I think I've figured out how to identify the computers IP, now I just need a bit of help figuring out how to change an IP address into a number that can be evaluated. This is what I have so far, but I am missing how to convert the IP somehow.
#!/bin/bash
ip=192.168.1.20
building1min=192.168.1.1
building1max=192.168.1.255
building2min=192.168.2.1
building2max=192.168.2.255
building3min=192.168.3.1
building3max=192.168.3.255
if [ $ip -lt $building1max && $ip -gt $building1min ]{
echo "User is in Building 1"
} else if [ $ip -lt $building2max && $ip -gt $building2min ]
echo "User is in Building 2"
} else if [ $ip -lt $building3max && $ip -gt $building3min ]{
echo "User is in Building 3"
} else {
echo "User is not in any building"
}

The following code should point you in the right direction:
#!/usr/bin/env bash
binary=( {0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1} )
convertToBinary() {
local -a oct
local o res ip=$1 mask=$2
IFS=. read -ra oct <<< "$ip"
for o in "${oct[#]}"; do
res+=${binary[o]}
done
printf '%s\n' "${res:0:mask}"
}
isInSubnet() {
local sub=$1 ip=$2
local sub_ip=${sub%/*} sub_mask=${sub#*/}
[[ $(convertToBinary "$sub_ip" "$sub_mask") = "$(convertToBinary "$ip" "$sub_mask")" ]]
}
# USAGE
ip=192.168.2.15
b1=192.168.1.0/24 b2=192.168.2.0/24
if isInSubnet "$b1" "$ip"; then
echo building 1
elif isInSubnet "$b2" "$ip"; then
echo building 2
fi
It first converts the IPs to binary and extracts only the network addresses that are then checked for equality.

Related

Ip host script bash

In the first if we want the hostname to appear, which is the 5th field from a file. Then if the IP we give to the host command does not exist, then the command returns message 3 (NXDOMAIN). The script should recognize if the command was "not found". In this case it will
must simply print (-).
#!/bin/bash
ip="$1"
if [ "$ip" ] ; then
host "$ip" | cut -d' ' -f5
elif
[[ "$ip" =~ "[3(NXDOMAIN)]$" ]] ; then
echo "-"
fi
Do u have any solution on this exercise?
You're not testing the result of the host command, you're testing the value of the original $ip variable.
Save the output to a variable, test that variable, then either print the output or - depending on the test.
You don't need to do a regexp match, just match the exact string.
#!/bin/bash
ip="$1"
if [ "$ip" ] ; then
result=$(host "$ip" | cut -d" " -f5)
if [[ $result = "3(NXDOMAIN)" ]] ; then
echo "-"
else
echo "$result"
fi
fi
The answer is much simpler than you think, you don't need to do any matching. You can just use the return code from host
#!/bin/bash
ip="$1"
if domain=$(host "$1"); then
echo "${domain##* }"
else
echo "-"
fi
Proof of Concept
$ testHost(){ if domain=$(host "$1"); then echo "${domain##* }"; else echo "-"; fi }
$ testHost 172.217.6.46
sfo03s08-in-f14.1e100.net.
$ testHost 172.217.6.466
-
#!/bin/bash
if [ -n "$1" ] && [[ $1 =~ ^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+$ ]] ;then
res=$(host "$1" | cut -d' ' -f5)
if [ "$res" != "3(NXDOMAIN)" ]; then
echo "$res"
else
echo "-"
fi
else
echo "please enter a valid ip"
fi
if you want to cover also ipv6 then I think this will cover it
#!/bin/bash
# ipv4
if [[ $1 =~ ^([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])\.([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])\.([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])\.([[:digit:]]{1,2}|1[[:digit:]][[:digit:]]|2[0-4][[:digit:]]|25[0-5])$ ]]; then
res=`host "$1" | cut -d' ' -f5`
if [ "$res" != "3(NXDOMAIN)" ]; then
echo "$res"
else
# valid ipv4 IP but not connected
echo "-"
fi
# ipv6
elif [[ $1 =~ ^(([[:xdigit:]]{1,4}:){7,7}[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}:){1,7}:|([[:xdigit:]]{1,4}:){1,6}:[[:xdigit:]]{1,4}|([[:xdigit:]]{1,4}:){1,5}(:[[:xdigit:]]{1,4}){1,2}|([[:xdigit:]]{1,4}:){1,4}(:[[:xdigit:]]{1,4}){1,3}|([[:xdigit:]]{1,4}:){1,3}(:[[:xdigit:]]{1,4}){1,4}|([[:xdigit:]]{1,4}:){1,2}(:[[:xdigit:]]{1,4}){1,5}|[[:xdigit:]]{1,4}:((:[[:xdigit:]]{1,4}){1,6})|:((:[[:xdigit:]]{1,4}){1,7}|:)|fe80:(:[[:xdigit:]]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]])|([[:xdigit:]]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[[:digit:]]){0,1}[[:digit:]]))$ ]]; then
res=`host "$1" | cut -d' ' -f5`
if [ "$res" != "3(NXDOMAIN)" ]; then
echo "1. $res"
else
# valid ipv6 IP but not connected
echo "2. -"
fi
else
echo "Please enter a valid IP"
fi
Note: For some versions of bash the -4 and -6 options do not work.
Thanks to Léa Gris for pointing out the locales problem.
Inspired from https://helloacm.com/how-to-valid-ipv6-addresses-using-bash-and-regex/

How to Validate IP address range (Shell Scripting)

I'm trying to figure out how to edit this script so it will validate an IP range instead of just one IP, i.e. 192.168.1.0/24.
echo "Target IP Address range or specific IP: "
read IPaddr
#IPv4 Validation
is_ip(){
local ip=$1
if expr "$ip" : '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' >/dev/null;then
for i in 1 2 3 4;do
if [ $(echo "$ip" | cut -d. -f$i) -gt 255 ];then
return 1
fi
done
return 0
else
return 1
fi
}
#Test User-inputted IPv4 Address
is_ip "$IPaddr"
if [[ $? -eq 0 ]]; then
echo "Valid IP address/range"
else
echo "Invalid IPv4"
exit 6
fi
This script seems to do what you want if I've understood your question properly.
#!/bin/bash
locInput="$1"
locIP=${locInput%\/*}
if [[ $locInput = #(*/*) ]];then
locRange=${locInput#*\/}
fi
function is_ip
{
if [[ $locIP == ?([0-9])+([0-9])\.?([0-9])+([0-9])\.?([0-9])+([0-9])\.?([0-9])+([0-9]) ]]; then
locVerif=(${locIP//./ })
for i in ${locVerif[*]}; do
if [[ $i -lt 0 || $i -gt 255 ]]; then
return 1
fi
done
if [[ -n $locRange && ($locRange -lt 0 || $locRange -gt 31) ]]; then
return 1
fi
return 0
else
return 1
fi
}
is_ip
if [[ $? -eq 1 ]]; then
echo "Wrong IP/Range"
else
echo "Good IP/Range"
fi
Hope it can help.

Netcat Chat bash script problems

I'm creating a sh script for a Chat using netcat.
This is the code:
#!/bin/bash
clear
echo
echo "-----------------------"
echo "| handShaker Chat 2.0 |"
echo "-----------------------"
echo
read -p 'Server or Client setUp? (s or c) > ' type
if [ $type == 's' ] || [ $type == 'S' ] || [ $type == 'server' ]
then
read -p 'Port (4321 Default) > ' port
if [ $port -gt 2000 ] && [ $port -lt 6500 ]
then
echo
echo "Started listening on port $port."
echo "Stream (Press ctrl + shift to end session) >"
echo
awk -W interactive '$0="Anonymous: "$0' | nc -l $port > /dev/null
else
echo "handShaker Error > The port $port is not a in the valid range (2000 ... 6500)."
fi
elif [ $type == 'c' ] || [ $type == 'C' ] || [ $type == 'client' ]
then
read -p 'Port (4321 Default) > ' port
if [ $port -gt 2000 ] && [ $port -lt 6500 ]
then
read -p 'Destination IP > ' ip
if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]
then
echo
echo "Started streaming $ip on port $port."
echo "Stream (Press ctrl + shift to end session) >"
echo
awk -W interactive '$0="Anonymous: "$0' | nc $ip $port > /dev/null
else
echo "handShaker Error > Invalid IP Address."
fi
else
echo "handShaker Error > The port $port is not a in the valid range (2000 ... 6500)."
fi
else
echo "handShaker Error > $type is not a valid keyword."
fi
But I have the following problems: the awk -W parameter doesn't seem to exist, and the program actually stops after running the client.
I'm using the macOS terminal.
Can someone help me to fix this bugs and to improve my script?
Your script has an incorrect & unnecessary usage of awk with -W interactive flags which are not defined in any of the flavours of awk. Removing it should solve your problem.
Also your script has a bunch of bash variables defined and used without double-quoting. Remember to double quote variables prevent globbing and word splitting.

how can i check IP version ( 4 or 6) in shell script

I want to check whether IP is of version 4 or version 6.
Input is IP Address in string form.
Example :
IP version 4 --> 1.1.1.1
IP version 6 --> 12:1201::12:15
You could check if the string contains a colon :, then it is an IPv6 address, otherwise it is an IPv4 addresss:
string='1.1.1.1';
if [[ $string =~ .*:.* ]]
then
echo "IPv6"
else
echo "IPv4"
fi
Native POSIX (no bashisms) solution without external calls:
#!/bin/sh
if [ "$1" != "${1#*[0-9].[0-9]}" ]; then
echo IPv4
elif [ "$1" != "${1#*:[0-9a-fA-F]}" ]; then
echo IPv6
else
echo "Unrecognized IP format '$1'"
fi
This uses POSIX replacements; ${1#*[0-9].[0-9]} is the first argument, replacing the first characters up to the first number-dot-number (so it won't match the unmodified first argument), which identifies an IPv4 address and ${1#*:[0-9a-fA-F]} is the same for a colon-hex, which identifies an IPv6 address. As a safety, I check both and have a fallback for invalid IPs.
This is not exact, it's merely fast. An exact match is possible in POSIX shell, but it's unwieldy.
In perl:
#!/usr/bin/perl
$_ = shift;
chomp;
if (/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ && $1<256 && $2<256 && $3<256 && $4<256)
{ $_ = "IPv4" }
elsif (/^(?!:\w)(?:::?[0-9a-f]{1,4}){1,8}$/i)
{ $_ = "IPv6" }
else
{ $_ = "Unrecognized IP format '$_'" }
print "$_\n";
in native POSIX:
#!/bin/sh
v4() { [ "$1" -lt 256 ] 2>/dev/null && [ $1 -ge 0 ] && [ $1 != "$2" ]; }
part="${1##*.}"
if v4 $part && v4 ${1%%.*}; then # test 1 & 4 from 1.2.3.4
part="${1%$part}" # 1.2.3.4 -> 1.2.3
part="${part#*.}" # 1.2.3 -> 2.3
if v4 "${part%.*}" && v4 "${part#*.}"; then # tests 2 & 3
echo IPv4
fi
# starts with hex, has colon AND lacks a nonhex/noncolon char
# AND lacks five consecutive hex chars and lacks 9 colons
elif [ "$1" != "${1#[0-9A-Fa-f]*:}" ] && [ "$1" = "${1#*[^0-9A-Fa-f:]}" ] \
&& [ "${1#*[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]}" \
= "${1#*:*:*:*:*:*:*:*:*:}" ]; then
echo IPv6
else
echo "Unrecognized IP format '$1'"
fi
To check IPV4:
ip='1.1.1.1'
awk -F. 'NF == 4' <<< "$ip"
1.1.1.1
To check IPV6:
ip='12:1201::12:15'
awk -F: 'NF>4' <<< "$ip"
12:1201::12:15

BASH Syntax Error - [: missing `]'

I am new to Bash programming and probably being really silly.
Basically I am writing a piece of script that will ping an IP Address I pass in, it will take from it packets transmitted and return an error or a pass message depending on the number of packets lost.
However whenever I run the script from my terminal I keep getting message -
./ipGatewayCheck.sh: line 13: [: missing]'`
This is my code:
#!/bin/bash
healthy_status=0
warning_status=10
critical_status=100
for gateway in $#
do
RESULT=`ping -q -c 10 $gateway | grep 'packets transmitted' | awk '{print $6}' | tr -d "%"`
echo "$RESULT"
if [ $RESULT -eq $healthy_status ]; then
echo "No Issue - IP Address is pinging"
elif [ $RESULT -ge $warning_status && -le $critical_status ]; then
echo "Warning - Issue with packet loss on this IP Address"
elif [ $RESULT -eq $critical_status ]; then
echo "Critical - 100% packet loss on this IP Address"
fi
done
Any help would be greatly appreciated.
You need to use [[ and ]] in order to use && inside square brackets:
if [[ "$RESULT" -eq "$healthy_status" ]]; then
echo "No Issue - IP Address is pinging"
elif [[ "$RESULT" -ge "$warning_status" && "$RESULT" -le "$critical_status" ]]; then
echo "Warning - Issue with packet loss on this IP Address"
elif [[ "$RESULT" -eq "$critical_status" ]]; then
echo "Critical - 100% packet loss on this IP Address"
fi
Alternatively you can also use (( and )) in BASH:
if (( RESULT == healthy_status )); then
echo "No Issue - IP Address is pinging"
elif (( RESULT == warning_status && RESULT < critical_status )); then
echo "Warning - Issue with packet loss on this IP Address"
elif (( RESULT == critical_status )); then
echo "Critical - 100% packet loss on this IP Address"
fi
As diagnosed by anubhava in his answer, the problem is that the && operator terminates the test command leaving you with a [ without a matching ] and the error message you get.
There's an alternative fix — more traditional shell coding and portable to shells other than Bash.
If you wish to use [, you have to use either the -a conjunction (instead of &&), or use two separate tests:
elif [ "$RESULT" -ge $warning_status -a "$RESULT" -le "$critical_status" ]; then
elif [ "$RESULT" -ge $warning_status ] && [ "$RESULT" -le "$critical_status" ]; then
Note that I had to add the second "$RESULT"; I also enclosed the variables inside double quotes to make sure there are no mishaps.

Resources