Bash Script Block All Apple Devices - linux

I am trying to create a shell script to block all apple devices on my network. I am using nmap for os detection. What I have so far is this:
while (true) do
nmap -O -T4 -p 22,80 -v 172.20.0.0/24 | grep -B9 'OS details: Apple' | \
grep 'Nmap scan report for' | cut -f4 -d'r' | cut -f2 -d' ' | \
iptables -i wlan0 -A INPUT -j DROP -s
sleep 10
done
Is there a way to simplify this at all so there is less grepping and cutting involved?
Also, this script will run into errors if there are more than one or zero apple devices found on the network. Is it possible to add logic for that?

Yes, of course it is possible. You can use perl/awk to simplify the script a lot.
Also, I'm not sure that your script is correct at the moment.
You have a pipe that write addresses to iptables, but iptables
doesn't work this way.
If you want to run iptables for each address that is produced by nmap,
you can read the addresses using read to some variable (in my example ADDR)
and then use the variable in iptables:
while (true) do
nmap -O -T4 -p 22,80 -v 172.20.0.0/24 | grep -B9 'OS details: Apple' | \
grep 'Nmap scan report for' | cut -f4 -d'r' | cut -f2 -d' ' | \
while read ADDR
do
iptables -i wlan0 -A INPUT -j DROP -s $ADDR
done
sleep 10
done

A few more remarks:
You do not need the parenthesis around true. This starts a new subshell, which is inefficient. In this case, you probably won't care, but it's good practice to avoid needless subshells.
the $ADDR in Igor Chubin's answer is dangerous. If $ADDR contains a whitespace character, it will be split up into separate parameters. Someone on the network may be able to affect the output of NMap, and modify the structure of the iptables command. Even if this is not the case here, it's good practice to put the argument in between double quotes whenever possible to prevent this: "$ADDR".
for similar reasons, you'll usually want to use read -r instead of just read. Without the -r parameter, backslash characters in the input will escape subsequent special characters (such as spaces).
NMap has its own Lua scripting support. This is another way to go at this problem, which may prevent you from having to parse any text at all.
If you are physically on the same network, you may be able to block Apple devices without any NMap at all, by blocking devices based on the MAC address of the device. The first three bytes identify the organisation which issued the MAC address. You can look them up here. They can be faked on a rooted device, but then again, so can the NMap fingerprinting (though that would likely be harder).

An important part of scripting is understanding the programs you are using and how to get the appropriate output from them. It looks like you have a decent understanding of Nmap, since you limit the number of ports scanned (-p 22,80) and request OS detection (-O), but you could avoid a lot of text processing if you used the appropriate output format.
Nmap's "grepable" format is deprecated, meaning that it can't be used to get a lot of more-recent features' output, but it works just fine for OS detection. You request it with -oG. Here's an example, borrowing some looping help from #IgorChubin's excellent answer:
while (true) do
nmap -O -T4 -p 22,80 -oG - 172.20.0.0/24 | awk '/OS: Apple/{print $2}' | \
while read ADDR
do
iptables -i wlan0 -A INPUT -j DROP -s $ADDR
done
sleep 10
done
Some other improvements include moving the sleep 10 into the while condition of the outermost loop, to allow killing it with Ctrl-C during one of the sleeps. Also, be aware that DHCP leases expire, and the IP you are blocking may be assigned to a different system in the future. In general, this approach does not seem like the best way to accomplish what you want.

Related

How to stop writing to a capture file using tcpdump after it reaches a specific size

I am looking for some solution to stop capturing the tcpdump packet after it capture a specified size .I am using the below command to achieve this but it looks like the tcpdump is not writing all the captured packet to the specified file(myfile.pcap).
sudo tcpdump -i en0 -C 10 -W 1 -z ./stop-tcpdump.sh -w myfile.pcap -K -n
cat stop-tcpdump.sh
#!/bin/sh
TCP_EXECUTABLE="tcpdump"
pid=$(pidof ${TCP_EXECUTABLE})
sudo kill -2 $pid
The easiest solution for tcpdump is probably just to increase -W 1 to -W 2. This will cause a 2nd capture file to begin to be written, but the 1st file of 10MB will remain fully intact instead of getting truncated, because the tcpdump instance won't necessarily be killed due to timing issues before that happens.
Alternatively, you could switch to using dumpcap or tshark, both of which support an explicit -a filesize:value option, so no post-rotate kill script is needed. Note that unlike tcpdump's -C option, this option expects the value in units of kB, not MB.

Raspberry pi 2 Hostapd Get list of users

So I set up my raspberry pi 2 with a hostapd that casts out an access point using my wlan0 interface along with dnsmasq and apache2 as my defualt browser. Now when i did this a year ago i could type the command:
arp -a
and it would show a list of the users that are on my network as such:`
*USERS NAME* 10.0.0.142 *mac adress*
along with other details. However, when i do it now, it only shows the ip address that they are on and the usual detail except for the users device name. instead of a device name i am shown "?" for all of the devices that are connected. I know my question might be a bit hard to follow but i hope someone can answer this question. Thank you.
You can print only Hostname of connected devices using the command:
arp | cut -d ' ' -f 1 | sed '1d'
it's better to add it to your aliases by editing the file .bashrc:
cd ~
sudo nano .bashrc
then press Ctrl+W and type alias to look for it, then you simply can insert your alias (at the end of system aliases) with desired name:
alias clients="arp | cut -d ' ' -f 1 | sed '1d'"
NOTE: be sure to use double quotations to enclose the command, or you can precede every single quotation with backslash \' in this case there is no need for "

Linux command for public ip address

I want command to get Linux machine(amazon) external/public IP Address.
I tried hostname -I and other commands from blogs and stackoverflow like
ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'
and many more. But they all are giving me internal IP Address.
Then I found some sites which provides API for this.
Example : curl http://ipecho.net/plain; echo
But I don't want to rely on third party website service. So, is there any command line tool available to get external IP Address?
simplest of all would be to do :
curl ifconfig.me
A cleaner output
ifconfig eth0 | awk '/inet / { print $2 }' | sed 's/addr://'
You could use this script
# !/bin/bash
#
echo 'Your external IP is: '
curl -4 icanhazip.com
But that is relying on a third party albeit a reliable one.
I don't know if you can get your external IP without asking someone/somesite i.e. some third party for it, but what do I know.
you can also just run:
curl -4 icanhazip.com
This is doing the same thing as a command the -4 is to get the output in Ipv4
You can use this command to get public ip and private ip(second line is private ip; third line is public ip.)
ip addr | awk '/inet / {sub(/\/.*/, "", $2); print $2}'
I would suggest you to use the command external-ip (sudo apt-get install miniupnpc) as it (I'm almost sure) uses upnp protocol to ask the router instead of asking an external website so it should be faster, but of course the router has to have upnp enabled.
You can simply do this :
curl https://ipinfo.io/ip
It might not work on amazon because you might be using NAT or something for the server to access the rest of the world (and for you to ssh into it also). If you are unable to ssh into the ip that is listed in ifconfig then you are either in a different network or dont have ssh enabled.
This is the best I can do (only relies on my ISP):
ISP=`traceroute -M 2 -m 2 -n -q 1 8.8.8.8 | grep -m 1 -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'`
extIP=`ping -R -c 1 -t 1 -s 1 -n $ISP | grep RR | grep -m 1 -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'`
echo $extIP
Or, the functionally same thing on one line:
ISP=`traceroute -M 2 -m 2 -n -q 1 8.8.8.8 | grep -m 1 -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'` | ping -R -c 1 -t 1 -s 1 -n $ISP | grep RR | grep -m 1 -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
to save it to a temporary & hidden file add > .extIP to the end of the last line, then cat .extIP to see it.
If your ISP's address never changes (honestly i'm not sure if it would or not), then you could fetch it once, and then replace $ISP in line two with it
This has been tested on a mac with wonderful success.
the only adjustment on linux that I've found so far is the traceroute "-M" flag might need to be "-f" instead
and it relies heavily on the ping's "-R" flag, which tells it to send back the "Record Route" information, which isn't always supported by the host. But it's worth a try!
the only other way to do this without relying on any external servers is to get it from curl'ing your modem's status page... I've done this successfully with our frontier DSL modem, but it's dirty, slow, unreliable, and requires hard-coding your modem's password.
Here's the "process" for that:
curl http://[user]:[password]#[modem's LAN address]/[status.html] | grep 'WanIPAddress =' | grep -m 1 -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
That fetches the raw html, searches for any lines containing "WanIpAddress =" (change that so it's appropriate for your modem's results), and then narrows down those results to an IPv4 style address.
Hope that helps!
As others suggested, we have to rely on third party service which I don't feel safe using it. So, I have found Amazon API on this answer :
$ curl http://169.254.169.254/latest/meta-data/public-ipv4
54.232.200.77
For more details, https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html#instancedata-data-retrieval
The super-easy way is using the glances tool. you can install it on Ubuntu using:
$ sudo apt install glances
then using it with:
$ glances
and at the top of the terminal, it highlights your public IP address, and so many other information about your system (like what htop does) and network status.
For a formatted output use :-
dig TXT +short o-o.myaddr.l.google.com #ns1.google.com
it'll give you formatted output like this
"30.60.10.11"
also FYI,
dig is more faster than curl and wget
The following works as long as you have ifconfig and curl.
curl ifconfig.me

Capture nethogs output in log file

I want to check the network bandwidth used by my process.
For this i found that nethogs tool is useful. Using this tool i can see which process is eating up a network bandwidth and process behaviour.
But how do I capture data from nethogs for a my process and store it into log file ?
You can run nethogs in background in tracemode and write output to a file like this:
sudo nethogs -t eth1 &> /var/tmp/nethogs.log &
Download and build the nethogs-parser as described here.
Then after you have accumulated enough data you can run the parser to see the results:
./hogs -type=pretty /var/tmp/nethogs.log
Make sure to kill the running nethogs process when you are done collecting data.
More info here on automating the task.
I dont know when these options got implemented but you can use nethogs -t or nethogs -b, the pid and user are strangely placed at the end of the pid command string, but easy enough to parse.
I think you need to use the latest cvs version 0.8.1-SNAPSHOT
You can use this command to capture output:
nethogs -d 5 | sed 's/[^[:print:][:cntrl:]]//g' > output.txt
The right command of nethogs is
nethogs -d 1 eth0 > output.txt
You need to specify the network interface otherwise, the default interface eth0 will be used. Sometime, nethogs might not show the proper output because of the network interface. It is always better to provide the network interface and generate some traffic during the experimentation. You can print the output to a file by adding > output.txt
-d argument specifies how frequently the output will be shown. Here, I gave 1, this indicates that the output will be shown per second.
Hope this might be useful.

How to modify input stream of netcat?

I'm creating a TCP/IP interface to a serial device on a redhat linux machine. netcat in a bash script was used to accomplish this with out to much trouble.
nc -l $PORT < $TTYDEVICE > $TTYDEVICE
The problem is that the serial device uses carriage returns('\r') for line ends in its responses. I want to translate this to ("\r\n") so windows machines telneting in can view the response without any trouble. I'm trying to figure out how to go about this with a simple bash solution. I also have access to stty to configure the serial device, but there is no "\r" to "\r\n" translate on the input side(from what I can tell).
I did try to use tr on the input side of netcat, but it didn't work.
#cat $TTYDEVICE | tr '\r' '\r\n' | nc -l $PORT > $TTYDEVICE
Any ideas?
Your problem is that the client that connects to $PORT probably does not have a clue that it is working with a tty on the other side, so you will experience issues with tty-specific "features", such as ^C/^D/etc. and CRLF.
That is why
socat tcp-listen:1234 - | hexdump -C
telnet localhost 1234
[enter text]
will show CRLFs, while
ssh -t localhost "hexdump -C"
[enter text]
yields pure LFs. Subsequently, you would e.g. need
ssh -t whateverhost "screen $TTYDEVICE"
tl;dr: netcat won't do it.
This is overly difficult with standard tools, but pretty easy in perl (although perl is pretty much a standard tool these days):
perl -pe 's/\r/\r\n/g'
The version above will likely read the entire input into memory before doing any processing (it will read until it finds '\n', which will be the entire input if the input does not contain '\n'), so you might prefer:
perl -015 -pe '$\="\n"'
There are a number of versions of netcat (GNU and BSD) but you might want to try:
-C Send CRLF as line-ending

Resources