<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>blog.mogosanu.ro &#187; expect</title>
	<atom:link href="http://blog.mogosanu.ro/tag/expect/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.mogosanu.ro</link>
	<description>the tutorial blog</description>
	<lastBuildDate>Sat, 03 Apr 2010 07:26:32 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>nat loopback, partea a ii-a</title>
		<link>http://blog.mogosanu.ro/shell-scripting/nat-loopback-partea-a-ii-a/</link>
		<comments>http://blog.mogosanu.ro/shell-scripting/nat-loopback-partea-a-ii-a/#comments</comments>
		<pubDate>Sun, 11 Oct 2009 12:48:23 +0000</pubDate>
		<dc:creator>spyked</dc:creator>
				<category><![CDATA[shell scripting]]></category>
		<category><![CDATA[/etc/crontab]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[expect]]></category>
		<category><![CDATA[iptables]]></category>
		<category><![CDATA[nat loopback]]></category>
		<category><![CDATA[wget]]></category>

		<guid isPermaLink="false">http://blog.mogosanu.ro/?p=87</guid>
		<description><![CDATA[În prima parte am discutat diverse metode de a accesa adresa (în cele mai multe cazuri, unul sau mai multe nume de site-uri interpretate de către un server web intern) externă a unei rețele din interiorul acesteia și ne-am oprit asupra cazulului particular în care router-ul are linux cu iptables instalat și putem adăuga două [...]]]></description>
			<content:encoded><![CDATA[<p>În <a href="http://blog.mogosanu.ro/retelistica/nat-loopback-partea-i/">prima parte</a> am discutat diverse metode de a accesa adresa (în cele mai multe cazuri, unul sau mai multe nume de site-uri interpretate de către un server web intern) externă a unei rețele din interiorul acesteia și ne-am oprit asupra cazulului particular în care router-ul are linux cu iptables instalat și putem adăuga două reguli suplimentare tabelei NAT.</p>
<p>Ne confruntăm aici cu o problemă: la restartarea router-ului, configurarea adițională se va pierde. În plus, softul acestuia nu permite adăugarea unor script-uri care să se execute la bootare și nici modificarea celor existente. Vom presupune că varianta schimbării firmware-ului (variantă care presupune riscul transformării router-ului într-o bucată de plastic bună de aruncat la gunoi, în cel mai rău caz) nu ne interesează, astfel că trebuie să transmitem totuși comenzile din exterior, prin telnet. Am presupus din capul locului că avem în rețea o mașină care rulează tot timpul, identificată prin <em>$server_ip</em>; adresa router-ului în rețea este <em>$router_ip</em>.</p>
<p>Automatizarea transmisiei de comenzi de la server către router se va face în două etape: prima, conceperea unui script care să comunice cu router-ul și a doua, verificarea la momente de timp prestabilite dacă regulile de NAT Loopback sunt în tabelă.</p>
<p><strong>1.Script-ul de introducere a regulilor în NAT-ul router-ului</strong></p>
<p>Pentru a putea comunica cu router-ul, trebuie în primul rând să știm cum va arăta shell-ul în sesiunea de telnet cu utilizatorul. De exemplu, pe modem-ul subsemnatului, ZTE931, prima dată se va cere user-ul și parola prin linii de forma „Login: ” și „Password: ”. Apoi va fi afișat un shell identificat prin string-ul „&gt; ”, iar după ce introduc comanda „sh” va fi afișat un alt shell, dat de „#”. Apoi, după fiecare comandă eu voi aștepta „#” de la modem.</p>
<p>Această comunicație poate fi automatizată folosind utilitarul <strong>expect</strong>, a cărui pagină de manual vă recomand să o consultați. Script-ul se va rula într-un shell special; se așteaptă răspunsuri de la o entitate folosind comanda <em>expect</em>, iar răspunsurile se trimit cu <em>send</em>. Mai concret, script-ul de update al tabelei NAT al router-ului va arăta astfel:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/usr/bin/expect -f</span>
spawn telnet <span style="color: #007800;">$router_ip</span> <span style="color: #666666; font-style: italic;">#deschid sesiunea telnet</span>
expect <span style="color: #ff0000;">&quot;Login: &quot;</span>
send <span style="color: #660033;">--</span> <span style="color: #ff0000;">&quot;admin<span style="color: #000099; font-weight: bold;">\r</span>&quot;</span>
expect <span style="color: #ff0000;">&quot;Password: &quot;</span>
send <span style="color: #660033;">--</span> <span style="color: #ff0000;">&quot;passgoeshere<span style="color: #000099; font-weight: bold;">\r</span>&quot;</span>
expect <span style="color: #ff0000;">&quot;&gt; &quot;</span>
send <span style="color: #660033;">--</span> <span style="color: #ff0000;">&quot;sh<span style="color: #000099; font-weight: bold;">\r</span>&quot;</span> <span style="color: #666666; font-style: italic;">#deschid shell pentru comenzi</span>
expect <span style="color: #ff0000;">&quot;#&quot;</span>
send <span style="color: #660033;">--</span> <span style="color: #ff0000;">&quot;iptables -t nat -A PREROUTING -d <span style="color: #007800;">$external_ip</span> -p tcp --dport 80 <span style="color: #000099; font-weight: bold;">\
</span>      -j DNAT --to <span style="color: #007800;">$server_ip</span>; iptables -t nat -A POSTROUTING -d <span style="color: #007800;">$server_ip</span> <span style="color: #000099; font-weight: bold;">\
</span>      -s 192.168.0.0/24 -p tcp --dport 80 -j SNAT --to <span style="color: #007800;">$router_ip</span>&quot;</span>
expect <span style="color: #ff0000;">&quot;#&quot;</span>
send <span style="color: #660033;">--</span> <span style="color: #ff0000;">&quot;exit<span style="color: #000099; font-weight: bold;">\r</span>&quot;</span> <span style="color: #666666; font-style: italic;">#inchiderea sesiunii</span>
expect <span style="color: #ff0000;">&quot;&gt; &quot;</span>
send <span style="color: #660033;">--</span> <span style="color: #ff0000;">&quot;exit<span style="color: #000099; font-weight: bold;">\r</span>&quot;</span></pre></div></div>

<p>Rularea acestui script bash/expect va substitui deschiderea unei sesiuni interactive și introducerea manuală a comenzilor de către utilizator. Script-ul poate fi executat de pe oricare mașină din rețeaua internă, după restartarea router-ului. Vom presupune că am numit acest script <strong>natloop</strong> și l-am salvat pe server-ul având adresa <em>$server_ip</em>, în directorul /router.</p>
<p><strong>2.Verificarea automată a existenței NAT Loopback</strong></p>
<p>Această problemă poate fi rezolvată în mai multe moduri. Unul din aceste moduri e chiar folosirea <em>expect</em> pentru verificarea tabelei NAT și update în cazul în care regulile nu există. Dar din moment ce am presupus că rezolvăm forward-ul către un server web, vom da o soluție un pic mai simplă: am spus că în cazul în care router-ul nu satisface NAT Loopback pe portul 80, vom fi direcționați către interfața web a acestuia. Un <strong>wget</strong> pe <em>$router_ip</em> (sau pe <em>$external_ip</em>, atunci când nu există NAT Loopback) va întoarce cel mai probabil un cod de eroare 401 (forbidden, deoarece nu au fost specificate user-ul și parola pentru sesiune). În schimb, dacă iau <em>$nume_domeniu</em> cu <em>wget</em>, voi primi 200 (eventual după câteva redirectări). Codul script-ului <strong>pingip</strong> (nume ales complet aleator, salvat probabil tot în /router) este următorul:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/bash</span>
<span style="color: #007800;">mesaj</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">wget</span> <span style="color: #007800;">$adr_domeniu</span> <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">1</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">grep</span> <span style="color: #660033;">-i</span> <span style="color: #ff0000;">&quot;HTTP request&quot;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">tail</span> <span style="color: #660033;">-n</span> <span style="color: #000000;">1</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">cut</span> <span style="color: #660033;">-d</span> <span style="color: #ff0000;">&quot; &quot;</span> -f6<span style="color: #000000; font-weight: bold;">`</span>
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #007800;">$mesaj</span> <span style="color: #000000; font-weight: bold;">!</span>= <span style="color: #000000;">200</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span> ; <span style="color: #000000; font-weight: bold;">then</span>
    <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$(date)</span> <span style="color: #007800;">$mesaj</span> Failed&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;&gt;</span> <span style="color: #000000; font-weight: bold;">/</span>router<span style="color: #000000; font-weight: bold;">/</span>nat.log
    <span style="color: #000000; font-weight: bold;">/</span>router<span style="color: #000000; font-weight: bold;">/</span>natloop
<span style="color: #000000; font-weight: bold;">else</span>
    <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$(date)</span> <span style="color: #007800;">$mesaj</span> Merge&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;&gt;</span> <span style="color: #000000; font-weight: bold;">/</span>router<span style="color: #000000; font-weight: bold;">/</span>nat.log
<span style="color: #000000; font-weight: bold;">fi</span></pre></div></div>

<p>Vom diseca întâi prima linie, care are rolul de a lua efectiv codul întors de cererea HTTP și a-l salva în variabila <em>$mesaj</em>. Practic, generez un flux de string-uri, executând <em>wget</em> pe una din adresele web externe ale server-ului și redirectând <em>stderr</em> către <em>stdout</em>. Acest flux îl filtrez cu un <em>grep</em> (doresc să știu doar codul întors de pagină, iar acesta are în față „HTTP Request&#8221;) și iau ultima linie, care va conține cel mai probabil ori 200 ori 401. Împart linia în coloane (după spații) folosind <em>cut</em> și iau a șasea coloană, care reprezintă codul propriu-zis.</p>
<p>Apoi tot ce fac este să verific dacă am un cod diferit de 200 și să rulez <em>natloop</em> în acest caz. Pentru a monitoriza activitatea script-ului, îl pun să scrie timestamp-ul și un mesaj (cod plus stare) într-un fișier pentru logging. Ce mai rămâne este adăugarea unei linii în /etc/crontab, pentru a executa script-ul nostru la anumite intervale de timp (eu l-am pus să facă verificarea la fiecare cinci minute, de exemplu).</p>
<p>Trebuie remarcat că e posibil ca acest exercițiu de scripting să nu dea întotdeauna rezultate corecte. Problema în sine e destul de complicată, deoarece presupune interdependența mai multor noduri din rețea (chiar și așa, putând fi complicată și mai mult în funcție de diverși factori). Personal, sugerez cititorului să înțeleagă și să se documenteze bine înainte să ruleze oricare din comenzile menționate aici (e de ajuns un comment și voi oferi lămuriri suplimentare dacă e nevoie). De asemenea, dacă cineva vine cu o soluție mai bună, sunt numai ochi.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mogosanu.ro/shell-scripting/nat-loopback-partea-a-ii-a/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

