I have a command line application which I use and also have to pass my local ip address as an argument, like:
jekyll --url 'http://192.168.1.2:3000' --pygments --safe --server 3000 --auto
I would like to make the url argument get my ip automatically, since I am always on different networks and get different loal ip addresses.
so I can use this alias in my .bashrc
alias jkl="jekyll --url 'http://$IP:3000' --pygments --safe --server 3000 --auto"
where $IP would be my local ip adress acquired dynamically.
Is there any way to do it?
First, use double quotes instead of single quotes around your $IP variable or else it won't interpolate the value
#!/bin/bash
# tested on bash 4
while read -r line
do
case "$line" in
"inet "* )
line="${line/inet /}"
line="${line%% *}"
if [[ ! $line =~ ^(127|172) ]] ;then
IP="$line"
echo "IP: $IP"
fi
;;
esac
done < <(ifconfig)
echo jekyll --url "http://$IP:3000" --pygments --safe --server 3000 --auto
Note that you will have a few different IPs in the output. Choose the one that fits your requirement most.
A computer does not necessarily have "a local IP address", there are often several. For instance, you typically have the localhost address (127.0.0.1), and one or more "true" externally visible addresses. It's hard for an automated solution to know which one to pick.
One easy solution is perhaps to hard-code the "eth0" interface (or whatever the name is of your most typical interface).
On Linux, you could use something like this:
$ ifconfig | grep -A1 eth0 | cut -d: -f2 | cut -d ' ' -f1 | grep \\.
192.168.0.8
So to stuff this into a variable (assuming bash) you would use
MY_IP=$(ifconfig | grep -A1 eth0 | cut -d: -f2 | cut -d ' ' -f1 | grep \\.)
Note that this hard-codes the interface name as eth0.
Related
NordVPN does not offer an automatic setup for linux, just VPN config files. What's the best way to implement this?
(my own implementation below, please feel free to comment or suggest improvements!)
EDIT: When I wrote this, I did not know that NordVPN did introduce a command line tool for linux recently.
I have written a little script that downloads the config files, renames them and enables automatic authentification. Insert your NordVPN login credentials in the generate authentification file part.
#!/bin/bash
# run as root!!!
# install openvpn. I'm running arch, this might be different on your system.
pacman -S openvpn
# go to openvpn config folder
cd /etc/openvpn
# download config files, extract and clean up
wget https://downloads.nordcdn.com/configs/archives/servers/ovpn.zip
unzip ovpn.zip
rm ovpn.zip
# rename tcp config files and put them in /etc/openvpn/client
cd ovpn_tcp
for file in *; do mv "${file}" "${file/.nordvpn.com.tcp.ovpn/}tcp.conf"; done
cp * ../client
# rename udp config files and put them in /etc/openvpn/client
cd ../ovpn_udp
for file in *; do mv "${file}" "${file/.nordvpn.com.udp.ovpn/}udp.conf"; done
cp * ../client
# generate authentification file
cd ../client
printf "<your email>\n<your password>" > auth.txt
# make all configs use authentification file
find . -name '*.conf' -exec sed -i -e 's/auth-user-pass/auth-user-pass\ auth.txt/g' {} \;
# clean up
cd ..
rm -r ovpn_tcp/
rm -r ovpn_udp
You can now start and stop vpn-connections via e.g.
systemctl start openvpn-client#de415tcp.service
and
systemctl stop openvpn-client#de415tcp.service
To automate this, and to connect to the server recommended by NordVPN, I have written two scripts. Make them executable and put them somewhere in your $PATH.
Pass a country code (like us, de or uk) as command line argument to start-vpn if you want to choose a specific country. It automatically chooses a tcp connection. You can change that to udp if you want.
start-vpn
#!/usr/bin/python
import sys
import requests
import os
import time
# you don't necessarily need the following. It's for monitoring via i3blocks.
def notify_i3blocks():
os.system('pkill -RTMIN+12 i3blocks')
def fork_and_continue_notifying_in_background():
newpid = os.fork()
if newpid == 0: # if this is the child process
for i in range(60):
notify_i3blocks()
time.sleep(1)
if __name__ == '__main__':
notify_i3blocks()
# below is what you do need.
suffix = ''
if len(sys.argv) > 1:
countries = requests.get('https://nordvpn.com/wp-admin/admin-ajax.php?action=servers_countries').json()
for country in countries:
if country["code"].lower() == sys.argv[1].lower():
suffix = '&filters={"country_id":' + str(country["id"]) + '}'
result = requests.get('https://nordvpn.com/wp-admin/admin-ajax.php?action=servers_recommendations' + suffix)
profile = result.json()[0]['subdomain'] + 'tcp'
command = 'systemctl start openvpn-client#' + profile + '.service'
os.system(command)
# the following is for i3blocks again.
fork_and_continue_notifying_in_background()
stop-vpn
#!/bin/bash
function service {
systemctl |
grep openvpn |
grep running |
head -n1 |
awk '{print $1;}'
}
while [[ $(service) ]]; do
systemctl stop $(service)
done
# notify i3blocks
pkill -RTMIN+12 i3blocks
For convenience, I have two aliases in my ~/.bashrc:
alias start-vpn='sudo start-vpn'
alias stop-vpn='sudo stop-vpn'
if you do want to monitor it via i3blocks, put this in your i3blocks config:
[vpn]
interval=once
signal=12
and this in your i3blocks-scripts-directory (with name vpn):
#!/bin/bash
function name {
systemctl |
grep openvpn |
grep running |
head -n1 |
awk '{print $1;}' |
cut -d # -f 2 |
cut -d . -f 1
}
starting=$(pgrep -f start-vpn) # this might not be the most accurate, but it works for me. Improvement suggestions are welcomed.
if [[ $(name) ]]; then
echo $(name)
echo && echo "#00FF00"
else
if [[ ${starting} ]]; then
echo starting vpn...
echo && echo "#FFFF00"
else
echo no vpn
echo && echo "#FF0000"
fi
fi
In order to automatically start and stop vpn when a network interface goes up/down, put the following in /etc/NetworkManager/dispatcher.d/10-openvpn. To activate the feature you need to enable and start the NetworkManager-dispatcher.service. More info here.
At my university, I connect to eduroam, which does not allow vpn. That's why I exclude that.
/etc/NetworkManager/dispatcher.d/10-openvpn
#!/bin/bash
case "$2" in
up)
if ! nmcli -t connection | grep eduroam | grep wlp3s0 ; then
start-vpn
fi
;;
down)
stop-vpn
;;
esac
I hope this helps other people who want to use NordVPN on linux. Again, feel free to comment and suggest improvements.
In particular, I am not sure how much of a security risk it is to have the NordVPN-password written out in plain text in a file.
Docker creates these virtual ethernet interfaces veth[UNIQUE ID] listed in ifconfig. How can I find out which interface belongs to a specific docker container?
I want to listen to the tcp traffic.
To locate interface
In my case getting value from container was like (check eth0 to):
$ docker exec -it my-container cat /sys/class/net/eth1/iflink
123
And then:
$ ip ad | grep 123
123: vethd3234u4#if122: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker_gwbridge state UP group default
Check with tcpdump -i vethd3234u4
Reference about mysterious iflink from http://lxr.free-electrons.com/source/Documentation/ABI/testing/sysfs-class-net:
150 What: /sys/class/net/<iface>/iflink
151 Date: April 2005
152 KernelVersion: 2.6.12
153 Contact: netdev#vger.kernel.org
154 Description:
155 Indicates the system-wide interface unique index identifier a
156 the interface is linked to. Format is decimal. This attribute is
157 used to resolve interfaces chaining, linking and stacking.
158 Physical interfaces have the same 'ifindex' and 'iflink' values.
Based on the provided answer (which worked for me), I made this simple bash script:
#!/bin/bash
export containers=$(sudo docker ps --format "{{.ID}}|{{.Names}}")
export interfaces=$(sudo ip ad);
for x in $containers
do
export name=$(echo "$x" |cut -d '|' -f 2);
export id=$(echo "$x"|cut -d '|' -f 1)
export ifaceNum="$(echo $(sudo docker exec -it "$id" cat /sys/class/net/eth0/iflink) | sed s/[^0-9]*//g):"
export ifaceStr=$( echo "$interfaces" | grep $ifaceNum | cut -d ':' -f 2 | cut -d '#' -f 1);
echo -e "$name: $ifaceStr";
done
My answer more like improvement on that important topic because it didn't help to "Find out which network interface belongs to docker container", but, as author noticed, he "want to listen to the tcp traffic" inside docker container - I'll try to help on that one during your troubleshooting of network.
Considering that veth network devices are about network namespaces, it is useful to know that we can execute program in another namespace via nsenter tool as follow (remember - you need a privileged permission (sudo/root) for doing that):
Get ID of any container you are interested in capture the traffic, for example it will be 78334270b8f8
Then we need to take PID of that containerized application (I assume you are running only 1 network-related process inside container and want to capture its traffic. Otherwise, that approach is hard to be suitable):
sudo docker inspect 78334270b8f8 | grep -i pid
For example, output for pid will be 111380 - that's ID of your containerized app, you can check also it via ps command: ps aux | grep 111380 just in curiosity.
Next step is to check what network interfaces you have inside your container:
sudo nsenter -t 111380 -n ifconfig
This command will return you list of network devices in network namespace of the containerized app (you should not have ifconfig tool on board of your container, only on your node/machine)
For example, you need to capture traffic on interface eth2 and filter it to tcp destination port 80 (it may vary of course) with this command:
sudo nsenter -t 111380 -n tcpdump -nni eth2 -w nginx_tcpdump_test.pcap 'tcp dst port 80'
Remember, that in this case you do not need tcpdump tool to be installed inside your container.
Then, after capturing packets, .pcap file will be available on your machine/node and to read it use any tool you prefer tcpdump -r nginx_tcpdump_test.pcap
approach's pros:
no need to have network tools inside container, only on docker node
no need to search for map between network devices in container and node
cons:
you need to have privileged user on node/machine to run nsenter tool
One-liner of the solution from #pbaranski
num=$(docker exec -i my-container cat /sys/class/net/eth0/iflink | tr -d '\r'); ip ad | grep -oE "^${num}: veth[^#]+" | awk '{print $2}'
If you need to find out on a container that does not include cat then try this tool: https://github.com/micahculpepper/dockerveth
You can also read the interface names via /proc/PID/net/igmp like (container name as argument 1):
#!/bin/bash
NAME=$1
PID=$(docker inspect $NAME --format "{{.State.Pid}}")
while read iface id; do
[[ "$iface" == lo ]] && continue
veth=$(ip -br addr | sed -nre "s/(veth.*)#if$id.*/\1/p")
echo -e "$NAME\t$iface\t$veth"
done < <(</proc/$PID/net/igmp awk '/^[0-9]+/{print $2 " " $1;}')
Hey there I want to write a script that will change the network profile settings (ifconfig, /etc/resolv.comf). Let the script retrieve and display the contents of the file with network profiles to root. The format of the database file will be in the form of: IP, IP Mask, Gateway. I've already done something but don't know if it's correct.
#!/bin/bash
IP=$(/sbin/ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1)
IPMask=$(/sbin/ifconfig eth0 | grep Mask | cut -d":" -f4)
Gateway=$(/sbin/ip route | awk '/default/ {print $3}')
echo "IP is : $IP"
echo "IP Mask is: $IPMask"
echo Gateway is: $Gateway"
The part I don't understand how to do is - Root interactively selects the network profile (by number), which is then activated. Any help please?
I have a lot of interfaces configured in my server, each of which connect to a specific nic card and have a separate routing table. These interfaces can be identified by "netstat -a" command.
Now, I want to execute the rsync command connecting only to specific interface. I have this requirement because each of the interfaces will go through a separate tunnel/path and I want a particular rsync command to sync files through a specified tunnel.
Specifically, I want a way to specify the interface name.
Thanks,
Mohan.
You can specify the address of the interface using --address=x.x.x.x on the command-line.
I don't think there is any way to specify the interface directly, but the ip command can tell you the address for an interface, so you could use something like this:
IP=$(ip -4 -br addr show eth0 | awk '{split($3,a,"/"); print a[1]}')
rsyncd ... --address=$IP
Edit For systems with the "real" iproute2 (anything not busybox-based, essentially), ip can produce JSON output which can be parsed a bit more sanely:
IP=$(ip -j -4 addr show wlo1 | jq .[0].addr_info[0].local)
rsyncd ... --address=$IP
I've written this little perl script to turn interface names to addresses, save it as iftoip (or similar)
#!/usr/bin/perl
use strict;
use warnings;
use IO::Interface::Simple;
use feature qw(say);
my $iface = shift;
my $if = IO::Interface::Simple->new($iface) or die "$!: $iface";
say $if->address;
exit 0;
You can do something similar with bash:
iftoip() {
ip addr show $1 | grep inet | awk '{print $2}' | cut -d'/' -f1
}
just add the above 3 lines to ~/.bashrc and start a new shell or source ~/.bashrc
Running it produces:
v#juno:~$ iftoip ens33
10.251.17.94
v#juno:~$ iftoip ens34
192.168.78.128
v#juno:~$ echo "IP=$(iftoip ens33)"
IP=10.251.17.94
v#juno:~$ iftoip ens35 #perl
No such device: ens35 at /home/v/bin/iftoip line 10.
or
v#juno:~$ iftoip ens35 #bash
Device "ens35" does not exist.
This has been tried using 2 interfaces, with different subnets and worked.
rsync -avzP -e 'ssh -b 10.100.16.X' /var/tmp/ent1 10.100.16.X:/var/tmp/;
rsync -avzP -e 'ssh -b 10.100.20.X' /var/tmp/ent2 10.100.20.X:/var/tmp/ ;
From client to server, over ssh use:
rsync -avP -e 'ssh -b x.x.x.x' tmp/ server:tmp/
I would like to extract the first part of this hostname testsrv1
from testsrv1.main.corp.loc.domain.com in UNIX, within a shell script.
What command can I use? It would be anything before the first period .
Do you have the server name in a shell variable? Are you using a sh-like shell? If so,
${SERVERNAME%%.*}
will do what you want.
You can use cut:
echo "testsrv1.main.corp.loc.domain.com" | cut -d"." -f1
To build upon pilcrow's answer, no need for new variable, just use inbuilt $HOSTANME.
echo $HOSTNAME-->my.server.domain
echo ${HOSTNAME%%.*}-->my
Tested on two fairly different Linux's.
2.6.18-371.4.1.el5, GNU bash, version 3.2.25(1)-release (i386-redhat-linux-gnu)
3.4.76-65.111.amzn1.x86_64, GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
try the -s switch:
hostname -s
I use command cut, awk, sed or bash variables
Operation
Via cut
[flying#lempstacker ~]$ echo "testsrv1.main.corp.loc.domain.com" | cut -d. -f1
testsrv1
[flying#lempstacker ~]$
Via awk
[flying#lempstacker ~]$ echo "testsrv1.main.corp.loc.domain.com" | awk -v FS='.' '{print $1}'
testsrv1
[flying#lempstacker ~]$
Via sed
[flying#lempstacker ~]$ echo "testsrv1.main.corp.loc.domain.com" | sed -r 's#([^.]*).(.*)#\1#g'
testsrv1
[flying#lempstacker ~]$
Via Bash Variables
[flying#lempstacker ~]$ hostName='testsrv1.main.corp.loc.domain.com'
[flying#lempstacker ~]$ echo ${hostName%%.*}
testsrv1
[flying#lempstacker ~]$
You could have used "uname -n" to just get the hostname only.
You can use IFS to split text by whichever token you want. For domain names, we can use the dot/period character.
#!/usr/bin/env sh
shorthost() {
# Set IFS to dot, so that we can split $# on dots instead of spaces.
local IFS='.'
# Break up arguments passed to shorthost so that each domain zone is
# a new index in an array.
zones=($#)
# Echo out our first zone
echo ${zones[0]}
}
If this is in your script then, for instance, you'll get test when you run shorthost test.example.com. You can adjust this to fit your use case, but knowing how to break the zones into the array is the big thing here, I think.
I wanted to provide this solution, because I feel like spawning another process is overkill when you can do it easily and completely within your shell with IFS. One thing to watch out for is that some users will recommend doing things like hostname -s, but that doesn't work in the BSD userland. For instance, MacOS users don't have the -s flag, I don't think.
Assuming the variable $HOSTNAME exists, so try echo ${HOSTNAME%%.*} to get the top-most part of the full-qualified hostname. Hope it helps.
If interested, the hint is from the below quoted partial /etc/bashrc on a REHL7 host:
if [ -e /etc/sysconfig/bash-prompt-screen ]; then
PROMPT_COMMAND=/etc/sysconfig/bash-prompt-screen
else
PROMPT_COMMAND='printf "\033k%s#%s:%s\033\\" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
fi
;; ... ```