Joaca cu Google Assistant(2)

Au trecut aproape 2 ani și jumătate de când am scris prima parte(link aici) iar în această perioadă s-au întâmplat multe în ceea ce privește automatizările pe care le-am făcut în casă. Vă recomand să citiți și prima parte pentru a avea mai mult context pentru ceea ce urmează.

După ce m-am distrat cu neopixelul, am vrut să îmi pornesc și să îmi opresc PC-ul tot așa folosind comenzi vocale.

Am analizat întâi ce implementări erau pe IFTTT pentru acest lucru și soluțiile propuse erau următoare:

  • Pentru pornire:
    1. Comanda vocală dată cu Google Assistant era preluată de IFTTT, iar ca execuție îți dădea trigger la o aplicație pe care trebuia să o ai instalată în telefon.
    2. Aplicația din telefon făcea la rândul ei trigger către o altă aplicație din telefon pentru Wake-on-LAN(WoL). Limitarea acestei soluții presupunea să ai telefon conectat la același WiFi în care se afla și PC-ul.
  • Pentru oprire:
    1. Comanda vocală dată cu Google Assistant era preluată de IFTTT, iar ca execuție îți scria un fișier în contul de Google Drive sau One Drive.
    2. Mai trebuia să ai o aplicație custom pe PC care rula ca și serviciu și îți monitoriza locul unde se sincroniza Google Drive sau One Drive. Când detecta un fișier într-un folder specific, apela în spate shutdown.

Soluțiile propuse atât pentru pornire cât și pentru oprire mi se păreau limitate și greoaie de aceea am luat decizia să îmi dezvolt propriile soluții.

Pentru pornire m-am folosit următoarele lucruri:

  • Aveam deja experința de la neopixel cu apelatul scriptului în python, deci râmanea doar să fac Wake-on-LAN via python. Wake-on-LAN este un protocol pentru pornirea calculatoarelor aflate în sleep sau complet oprite. Pentru a putea fi „trezit” calculatorul este nevoie să fie activată din BIOS funcția de Wake-on-LAN și pe PC-urile cu Windows mai trebuie făcute ceva setări în plus la placa de rețea. Principiul după care funcționează este următorul – calculatoarele oprite așteaptă să primească un Magic Packet pe portul LAN. Pachetele de genul pot fi trimise de pe routere sau diferite softuri. Pachetul se trimite ca și broadcast în rețea și conține adresa MAC a plăcii de rețea a PC-ului pe care dorim să îl pornim.
  • Nu am vrut să implementez de la 0 trimiterea pachetului magic în python așa că am folosit pachetul python wakeonlan în scriptul meu.
from wakeonlan import send_magic_packet
send_magic_packet("F0.2F.AA.DB.63.AA")

Pentru oprire am stat mai mult ca să găsesc o soluție care să nu implice softuri externe și singura soluție la care am ajuns a fost să am o conexiune prin SSH între Raspberry Pi și PC, iar de pe Raspberry să vină comanda de shutdown. Pașii pentru dezvoltarea acestei soluții au fost următorii:

  • Mi-am instalat pe PC serverul de SSH default de la Microsoft.
  • Mi-am modificat autentificarea pe bază de utilizator/parolă în autentificare pe bază de chei.
  • Cheile generate la pasul anterior le-am mutat și pe Raspberry Pi.
  • Când venea un request pe server web, se apela următorul script în bash.
#!/bin/bash
ssh andrei@192.168.1.50 "shutdown 0" & exit;

După câteva ore și teste m-am gândit că decât să oprească PC-ul mai bine să îl pună pe sleep.

ssh andrei@192.168.1.50 "rundll32.exe powrprof.dll,SetSuspendState 0,1,0" & exit;

Un lucru important pe care vreau să îl menționez este faptul că eu în rețeaua mea folosesc IP-uri statice pentru PC-uri, Raspberry Pi și cam orice este legat pe fir, deoarece uneori nu mergea conectarea prin ssh folosind numele device-ului.

Arhitectura soluției

În imaginea de mai sus se mai pot observa două lucruri:

  1. Un POST request de la IFTTT către ISP.
    ISP-ul meu este Digi iar conexiunea mea la internet este de tipul PPPoE. Asta înseamnă că IP-ul pe care mi-l asignează este dinamic iar la o conectare ulterioară(în cazul unui restart al routerului din varii motive) să fie altul decât acela pe care l-am avut.
    Dacă totuși vrei o conexiune către rețeaua ta de acasă, cei de la Digi îți oferă gratuit serviciul de Dynamic Domain Name System(DDNS). Tot ce trebuie să faci este să intri în contul tău Digi și să îți alegi un nume pentru subdomeniu și vei putea folosi acest subdomeniu ca să îți poți accesezi resursele din rețeua internă. Subdomeniile oferite de Digi sunt de forma: numeAles.go.ro unde numeAles este subdomeniul ales de mine.
    Mecanismul din spatele DDNS într-o explicație mai simplă este următorul: în loc să folosești IP-ul, folosești subdomeniu iar de traducerea din subdomeniului în IP se ocupă serverul de DDNS.
    ex: GET request către http://numeAles.go.ro/pagina1.html va face în spate un request către http://86.125.142.34/pagina1.html.
  2. Un port forwarding de pe portul 80 al routerului pe portul 80 al Raspberry Pi-ului.
    Pentru accesa o resursă privată din internet va fi nevoie ca requestul care va veni pe router să fie redirecționat către device-ul din rețea care conține resursa. Redirecționarea presupune deschiderea unui port extern pe router unde vor ajunge requesturile iar pachetele de date care vor ajunge pe router la acel port vor fi trimise către un anumit IP și port din rețeaua privată.
    ex: GET requestul http://86.125.142.34/pagina1.html ajunge pe router. Portul 80 este deschis și este setat în router să facă redirecționare către Raspberry Pi tot pe portul 80, deci requestul nostru va fi ca și requestul http://192.168.1.20/pagina1.html făcut din rețeaua privată.

Soluția descrisă mai sus a funcționat fără nici o problemă pe NUC pentru că pe el am făcut dezvoltarea ei(februarie 2021) dar nu a funcționat cum trebuie partea de pornire pentru PC(PC-ul l-am construit în aprilie 2021 și problema era că nu voia să se „trezească” când venea Magic Packet decât dacă era în sleep. O să detaliez într-un alt articol cum am rezolvat problema pentru că mi-am bătut capul cu ea aproape 2 ani – Update: link articol).

În luna iulie 2021 am revenit la Cluj ca să îmi susțin disertația, pe atunci încă stăteam la cămin iar device-urile au rămas la Sighișoara. La începutul lunii septembrie m-am mutat în chirie, mi-am făcut abonament la Digi și mi-am adus cam toate device-urile la Cluj. Mi-am luat un router nou și am asignat IP-urile private la device-uri în așa fel încât să fie ca pe cel din Sighișoara. Pe abonamentul nou creat mi-am activat DDNS iar în POST requesturile făcute de IFTTT am schimbat subdomeniul.

Totul era funcțional și mergea cum trebuie până într-o dimineață(octombrie 2021) când m-am trezit și am observat că NUC-ul era pornit(pe atunci nu puteam să îl pornesc din buton pentru că se oxidase ceva contact la el și singurul mod de pornire era WoL) și neopixelul era aprins și lumina foarte puternic în ceva culoare aleatoare. Mă gândeam dacă am vorbit ceva în somn și Google a interpretat dar am zis că mai bine să verific logurile serverului de Apache. Am văzut acolo în listă o grămadă de încercări de POST/GET request-uri de la diferite IP-uri de prin Asia și după mi-a picat fisa că am fost atacat.

Site-ul așa cum arăta în ziua atacului.

Site-ul meu web era ceva simpluț un pic de html cu php, ceva butoane și cam atât. Ce nu m-am gândit să îi pun a fost o metodă de autentificare și de aici faptul că oricine din internet putea să facă requesturi către el. Cel mai probabil cineva a scanat întreg subnetul din care făcea parte și IP-ul pe care îl aveam de la ISP și găsind portul 80 deschis a dat în el cu tot ce a putut(prin loguri se vedeau încercări cu diferite tooluri din Metasploit).

Văzând cele întâmplate am dezactivat port fordwaring de pe portul 80 și am hotărât să caut o altă soluție care să fie sigură atunci când se fac requesturi dinspre IFTTT spre rețeaua mea.
În următoarele părți ale acestei serii o să vă prezint ce soluții am mai încercat și cum am ajuns la o soluție finală.

Răspunsuri la „Joaca cu Google Assistant(2)”

  1. […] problema prezentată în partea a doua(link aici) am vrut să folosesc soluții de home automation care să permită atât integrări cu […]

  2. […] în articolul Joaca cu Google Assistant(2) de faptul că Wake-on-LAN(WoL) nu funcționa corespunzător pe PC. PC-ul se „trezea” când […]

Lasă un comentariu

Acest site folosește Akismet pentru a reduce spamul. Află cum sunt procesate datele comentariilor tale.