Drukarka sieciowa w sieci bez dostępu do routera (zmienne IP)

Przypadek zwykłego użytkownika

Dostawca internetu znajomych owszem zapewnia prekonfigurowany router. Jednak bez możliwości zarządzania nim. Oznacza to, że w sieci domowej danego użytkownika, czyli po stronie klienta, nie ma możliwości samodzielnego zarezerwowania adresu IP dla drukarki sieciowej.

Zapytawszy wsparcie, czy jest możliwość rezerwacji adresu IP otrzymałem odpowiedź, że jest. Koszt to 10 PLN.
Co miesiąc.

Dokąd mnie to wszystko prowadzi? Z jednej strony nie mogę zmienić konfiguracji DHCP na routerze, a z drugiej nie chcę w samej drukarce ustawiać adresów na sztywno - nie chcę ryzykować konfliktów IP. No i obstawiam, że ktoś pewnego dnia będzie chciał z tej drukarki skorzystać na innym routerze i w innej sieci.

**Co chciałem osiągnać **(i osiągnąłem)

To nie jest przypadek z miejsca pracy, gdzie nie ma podobnych ograniczeń, czy też z domu, gdzie jest dostępny w pełni konfigurowalny router, na którym do kompletu jest jakaś fajna dystrybucja WRT z usługą DNS.

A ja chcę, by *CUPS *miał zawsze to samo wskazanie do tej drukarki, czyli:

socket://{{ stała wartość }}:PORT

**
Co z tym zrobiłem**

Ostatecznie oskryptowałem aktualizację wpisu w /etc/hosts. Sam adres IP drukarki znajduję po jej mac adresie, a skrypt dodałem do crona.

**Z czego skorzystałem **(lub nie skorzystałem)

arp-scan -lx

Działa wybornie i jest dość idiotoodporny. W skrypcie wywołanym osobno na Debianie i openSUSE działa fajnie. Jednak na Debianie, gdy skrypt wywołany jest przez cron, nie dostaję zwrotki z arp-scan do dalszego przetwarzania wewnątrz skryptu. Nie analizowałem jeszcze, dlaczego tak się dzieje i polecenie arp-scan zastąpiłem przez nieco trudniejsze przy przetwarzaniu:

nmap -sP

Jeżeli IP jest już rozwiązane jakąś nazwą, to w zwrotce z nmap zmienia się struktura wiersza Nmap scan report for (…), więc IP może być na piątym lub szóstm miejscu w nawiasach lub bez nich. Nie chciałem też poświęcać czasu na wyciąganie sedem grupy z IP albo testowanie rozwiązań znalezionych przez wyszukiwarkę internetową, co potrafi zająć jeszcze więcej czasu. Czasu, który przecież mogę poświęcić na ten wpis i podzielić się “życiowym przypadkiem”. :slight_smile:

Polecenie nmap IP zwraca exit code 0:

tumbleweed:~ # nmap 10.10.10.10
Starting Nmap 7.92 ( https://nmap.org ) at 2021-12-27 19:11 CET
Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn
Nmap done: 1 IP address (0 hosts up) scanned in 3.09 seconds
tumbleweed:~ # echo $?
0

Z lenistwa, wróć… z oszczędności czasu nie sprawdzałem, czy można dla nmap wymusić exit code różny od 0 i nie oskryptowywałem też jego outputu - znów ta oszczędność czasu! Mimo wszystko walidacja znalezionego IP jest potrzebna i tutaj zwykły ping wydajnie wystarczył.

Zdecydowałem się też nie tworzyć osobnego pliku logu, a komunikaty przekazuję przy pomocy polecenia logger.

Co mi wyszło

#!/usr/bin/sh

# a script to find the IP of my lan printer

SCRIPTNAME=$0
HOSTSFILE="/etc/hosts"
TARGETNET="YYY.YYY.YYY.YYY/ZZ"
PRINTERMAC="XX:XX:XX:XX:XX:XX"
PRINTERALIAS="wlanprinter"
DOMAIN="mydomain"
RET="empty"

# catch printer IP and perform simple check of it
PRINTERIP="$(nmap -sP ${TARGETNET} | grep -i -B 2 ${PRINTERMAC} | head -n 1 | rev | cut -f 1 -d ' ' | rev | tr -d '()')"

ping -c 1 ${PRINTERIP} >/dev/null 2>&1

if  $? -eq 0 ]; then
  logger "${SCRIPTNAME}: printer IP ${PRINTERIP} was pinged successfully."
else
  logger "${SCRIPTNAME}: printer IP ${PRINTERIP} ping failed. Exiting."
  exit 1
fi

# check and update hosts file
grep -q "${PRINTERALIAS}" ${HOSTSFILE} && RET="OVERWRITE" || RET="MISSING"

case "$RET" in
  OVERWRITE)
    sed -i "s/.*${PRINTERALIAS}.*/${PRINTERIP} ${PRINTERALIAS}.${DOMAIN} ${PRINTERALIAS}/" ${HOSTSFILE}
    ;;
  MISSING)
    echo >> ${HOSTSFILE}
    echo "### modified by ${SCRIPTNAME}" >> ${HOSTSFILE}
    echo "${PRINTERIP} ${PRINTERALIAS}.${DOMAIN} ${PRINTERALIAS}" >> ${HOSTSFILE}
    ;;
  *)
    logger "${SCRIPTNAME}: grepping the given host file failed. Exiting."
    exit 1
    ;;
esac

# check hosts file
grep -q "${PRINTERIP} ${PRINTERALIAS}.${DOMAIN} ${PRINTERALIAS}" ${HOSTSFILE}

if  $? -eq 0 ]; then
  logger "${SCRIPTNAME}: ${PRINTERALIAS} is pointing to ${PRINTERIP}. Ended successfully."
  exit 0
else
  logger "${SCRIPTNAME}: veryfing the ${HOSTSFILE} failed. Exiting."
  exit 1
fi

I jak to wszystko zadzialało i wszyscy byli szczęśliwi, to…

Co mi się nie podoba w tym rozwiązaniu
Myślę, że logika dla skryptu powinna być następująca:

  • sparwdziić zawartość /etc/hosts,
  • jeżeli jest w nim IP przypisany dla aliasu drukarki, to sprawdzić go z jej mac adresem,
  • /etc/hosts aktualizować wyłącznie, gdy w /etc/hosts istnieje stary lub niepoprawny wpis.

**Co mi się podoba
**Bardzo podoba mi się lakoniczne, lecz wydajne sprawdzanie czy coś jest, czy tego nie ma, a w analogicznych przypadkach, czy działa, czy nie działa przy pomocy składni:

grep -q "${PRINTERALIAS}" ${HOSTSFILE} && RET="OVERWRITE" || RET="MISSING"

Podoba mi się też to, że to ja decyduję, w którym momencie skrypt ma się zakończyć pomyślnie lub z błędem.