Узнать белый IP-адрес роутера с сервера, который за NAT-ом

В свое время устроился на работу приходящим админом в небольшую организацию. Интернет раздавался через один компьютер (назовем его шлюзом), который бриджем устанавливал соединение по ADSL с динамическим белым IP.

Так как постоянно я не находился в офисе, для оперативного решения мелких вопросов нужен был удаленный доступ в локальную сеть организации. После избавления на шлюзе винды (да там была Windows XP и Kerio Winroute Firewall) и установки CentOS 6, задался вопросом о постоянной возможности коннекта к шлюзу.

Уже был положительный опыт использования dynamic dns сервисов (на домашнем роутере), поэтому была заведена отдельная учетка на dyndns.org.
Далее был на шлюз был установлен пакет inadyn (как один из рекомендуемых самим dyndns.org).

После этого были написаны 2 bash скрипта. Оба запускаются по крону, первый каждые 5 минут, второй — каждую неделю. Сделано это было по следующей причине.
Если каждые 5 минут отправлять на сервер свой неизменный IP, тогда после определенного количества попыток dyndns.org просто заблокирует четную запись, и разблокировать снова можно, только зайдя в учетную запись. Поэтому первый скрипт перед отправкой своего IP на dyndns.org сначала его проверяет — отличается ли текущий реальный IP от того, который выдает сам сервис dyndns.org на доменное имя.
Второй скрипт нужен, чтобы сервис dyndns.org не забывал об этом аккаунте, т.к. опять же в бесплатном режиме если к сервису dyndns.org долго не обращаешься — то опять идет блокировка аккаунта. Поэтому второй скрипт отправляет IP всегда, даже если он не изменился.

Собственно теперь сами скрипты.
Первый ipupdate:

#!/bin/sh
logger -t ipupdate "UPDATING IP START"

# HOSTNAME is your DynDNS hostname
HOST2=my-remote-server.dyndns.org
HOST3=my-remote-server-other.dyndns.org

# NSLOOKUP is the current DNS entry for your DynDNS hostname
OLD_IP2=`/usr/bin/nslookup -sil $HOST2 | tail -2 | head -1 | cut -d" " -f2 | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`
if [ "$OLD_IP2" = "" ]  ; then
    logger -t ipupdate "Not entry IP for $HOST2. Second empty..."
    OLD_IP2=`ping $HOST2 -c 1 | head -1 | cut -d" " -f3 | sed 's/(//' | sed 's/)//' | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`
fi
if [ "$OLD_IP2" = "" ]  ; then
    logger -t ipupdate "Not entry IP for $HOST2. Second empty: FAILED"
fi

OLD_IP3=`/usr/bin/nslookup -sil $HOST3 | tail -2 | head -1 | cut -d" " -f2 | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`
if [ "$OLD_IP3" = "" ]  ; then
    logger -t ipupdate "Not entry IP for $HOST3. Second empty..."
    OLD_IP3=`ping $HOST3 -c 1 | head -1 | cut -d" " -f3 | sed 's/(//' | sed 's/)//' | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`
fi
if [ "$OLD_IP3" = "" ]  ; then
    logger -t ipupdate "Not entry IP for $HOST1. Second empty: FAILED."
fi

if [ "$OLD_IP2" = "" ] && [ "$OLD_IP3" = "" ] ; then
    logger -t ipupdate "CHECKING INTENAL IP FAILED"
    logger -t ipupdate "EXIT"
    exit
fi

# Services for check external ip
CHECK_IP0='ifconfig.me/ip'
CHECK_IP1='http://checkip.dyndns.com'
CHECK_IP2='http://2ip.ru'
CHECK_IP3='http://www.netins.net/dialup/tools/my_ip.shtml'

logger -t ipupdate "$HOST2 has IP: $OLD_IP2"
logger -t ipupdate "$HOST3 has IP: $OLD_IP3"

logger -t ipupdate "Check external IP throw $CHECK_IP0"
CURRENT_IP=`/usr/bin/curl $CHECK_IP0 | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`

if [ "$CURRENT_IP" = "" ]; then
    logger -t ipupdate "Checking external IP throw $CHECK_IP0 FAILED"
    logger -t ipupdate "Check external IP throw $CHECK_IP2"
    CURRENT_IP=`/usr/bin/lynx -dump $CHECK_IP1 | awk '/Current IP Address:/ { print $4; }' | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`
fi

if [ "$CURRENT_IP" = "" ]; then
    logger -t ipupdate "Checking external IP throw $CHECK_IP1 FAILED"
    logger -t ipupdate "Check external IP throw $CHECK_IP2"
    CURRENT_IP=`/usr/bin/lynx -dump $CHECK_IP2 | awk '/Ваш IP адрес:/ { print $4; }' | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`
fi

if [ "$CURRENT_IP" = "" ]; then
    logger -t ipupdate "Checking external IP throw $CHECK_IP2 FAILED"
    logger -t ipupdate "Check external IP throw $CHECK_IP3"
    CURRENT_IP=`/usr/bin/lynx -dump $CHECK_IP3 | grep -A2 "Your current IP Address is:" | tail -n1 | tr -d ' '|sed '/^$/d'| sed 's/^ *//g' | grep '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`
fi

if [ "$CURRENT_IP" = "unknown" ] || [ "$CURRENT_IP" = "" ] ; then
    logger -t ipupdate "Checking external IP throw $CHECK_IP3 FAILED"
    logger -t ipupdate "CHECKING EXTERNAL IP FAILED"
    logger -t ipupdate "EXIT"
    exit
fi
logger -t ipupdate "Real IP: $CURRENT_IP"

if [ "$OLD_IP2" != "$CURRENT_IP" ] || [ "$OLD_IP3" != "$CURRENT_IP" ] ; then
    logger -t ipupdate "IP need to update"
    if [ "$OLD_IP2" != "$CURRENT_IP" ] ; then
        inadyn --input_file /etc/inadyn/remote1.conf
    fi
    if [ "$OLD_IP3" != "$CURRENT_IP" ] ; then
        inadyn --input_file /etc/inadyn/remote2.conf
    fi

    logger -t ipupdate "sleeping for 30 sec"
    sleep 30

    logger -t ipupdate "daemon for updating has stoped"
    killall inadyn

    # Flush local DNS cache of $HOSTNAME
    /sbin/service named restart
    else
    logger -t ipupdate "Current IP is actual"
fi
logger -t ipupdate "UPDATING IP FINISHED"
exit

my-remote-server.dyndns.org и my-remote-server-other.dyndns.org — это примеры алиасов с разных учеток. Мне нужно больше 2х ДНС-имен, поэтому зарегистрировал 2 учетки. Проверка IP адресов идет по все ДНС-именам.

remote1.conf и remote2.conf — конфиги разных учеток для dyndns.org.
logger — записывает в стандартный лог фразу, можно убрать — на работу не скажется

Второй ipupdWeek:

#!/bin/sh
logger -t ipupdWeek "WEEK UPDATING IP START"

# script name of updating IP
script='ipupdate'

# check for running of script of update IP
scriptRunning=`/bin/ps aux | grep $script | grep -v 'grep'`

if [ "$scriptRunning" = "" ]; then
    logger -t ipupdWeek "Script of updating IP IS NOT running"
    echo "Not running"
else
    logger -t ipupdWeek "Script of updating IP IS RUNNING, killall it"
    killall $script
fi

logger -t ipupdWeek "Start inadyn to update all IP"
inadyn --input_file /etc/inadyn/remote1.conf
inadyn --input_file /etc/inadyn/remote2.conf

logger -t ipupdWeek "Sleeping 10 sec"
sleep 10

logger -t ipupdWeek "Stop inadyn"
killall inadyn
logger -t ipupdWeek "WEEK UPDATING IP STOP"
exit

Здесь думаю все понятно.

Вот эти 2 скрипта с минимальными изменениями (добавил еще сервисы для проверки текущего IP) уже работают больше 2х лет. Перебои с электроэнергией и интернетом не страшны — после установки интернет-соединения в течение 5 минут (можно изменить в кроне) я снова буду иметь возможность удаленно подключиться.

P.S. Не претендую на что-то оригинальное, но в свое время пришлось потратить время на эти скрипты, надеюсь этот пост кому-то поможет это время сэкономить.

P.P.S. Чтобы вообще не заморачиваться со всем этим — модем в режим роутера (само собой проброс портов) и настроить dyndns в самом модеме.
На тот момент, когда все это делал — модем загибался от работы в режиме роутера. Сейчас с новым модемом — пока не вижу смысла что-то менять, ибо «работает — ради бога не трогай» (с).