dues versions de python en un host
A vegades cal fer algún invent extrany amb el python, com per exemple, el haver de tenir dues versions instal·lades. Sovint la nostre distribució ja portarà una versió del mateix i a més moltes eines de les distribucions acostumen a anar lligades a aquesta versió que millor no malmetre.
Cookbook d’ordres per instal·lar un python 2.6.5 a més del 2.4.3 que ja portava el host:
cd /var/tmp
wget http://python.org/ftp/python/2.6.5/Python-2.6.5.tar.bz2
tar xvfj Python-2.6.5.tar.bz2
cd Python-2.6.5
./configure --prefix=/usr
make
make altinstall
si ara fem:
# python -V
Python 2.4.3
# python2.4 -V
Python 2.4.3
# python2.6 -V
Python 2.6.5
long polling amb jquery+jsonp+couchdb (cross domain suportat)
Porto mesos somiant amb fer la prova de concepte que explico en aquest article, intentaré descriure en que consisteix però ja aviso que la cosa és un pèl complicadilla.
Funcionalitats requerides:
- long polling: l’objectiu és rebre els canvis d’una base de dades de couchdb en temps real sense haver d’anar preguntant si hi ha canvis, sinó que aquest s’envien cada vegada que es donen de forma automàtica.
- A través de jQuery el que vull és actualitzar una pàgina web de forma asíncrona, de forma que els nous resultats que vagin entrant a la BBDD es vagin mostrant en temps real a la pantalla.
- JSONP, és una tècnica que ens permet rebre la sortida JSON de CouchDB i després cridar una funció de callback de JavaScript. El problema és que la funció jQuery.getJSON() original de jQuery té algunes mancances que gràcies a el plugin jQuery-JSONP podem solucionar, aquestes són: (copy/paste de la web del plugin)
- error recovery in case of network failure or ill-formed JSON responses,
- precise control over callback naming and how it is transmitted in the URL,
- multiple requests with the same callback name running concurrently,
- two caching mechanisms (browser-based and page based),
- the possibility to manually abort the request just like any other AJAX request,
- a timeout mechanism.
- CouchDB és una base de dades NoSQL basada en documents que és capaç d’emetre una senyal (trigger) cada vegada que el contingut d’una base de dades canvia. Per més informació sobre el tema es pot consultar a: CouchDB: The Definitive Guide al capítol Change Notifications.
- Cross-domain: quan es llença una petició XmlHttpRequest (la base del AJAX) amb JavaScript tenim la limitació de només poder-ho fer sobre el domini que serveix la pàgina web, cap altre port ni subdomini. Obviament tampoc un altre host. Per saltar-se aquesta restricción és quan cal recorrer a JSONP.
La prova de concepte ha estat crear una base de dades anomenada: notifcations on es guarden documents que són notificacions a mostrar a la pàgina web.
Després he programat la següent web:
<html> <head> <script type="text/javascript" src="jquery-1.4.2.min.js"></script> <script type="text/javascript" src="jquery.jsonp-1.1.4.js"></script> <script type="text/javascript"> function longpoll(since) { var url = "http://IP_COUCHDB_SERVER:5984/notifications/_changes?include_docs=true&feed=longpoll&since="+since+"&callback=?"; console.log("since="+since); $.jsonp({ "url":url, "success":function(data) { //console.log(data); since=data.last_seq; try { console.log(data.results[0].doc.msg); } catch(err) { console.log("error:"+err); }; longpoll(since); }, "error":function(msg) { //console.log(msg); console.log('capturat error'); } }); }; var url = "http://IP_COUCHDB_SERVER:5984/notifications?callback=?"; $.jsonp({ "url":url, "success":function(data) { //console.log(data); longpoll(data.update_seq); }, "error":function(msg) { console.log(msg); } }); </script> </head> <body> cos </body> </html>
El codi és força simple de seguir, primer de tot es carreguen les llibreries: jQuery 1.4.2 i jquery-jsonp 1.1.4, ambdues necessaries per cridar el métode $.jsonp que és el que realment farà la feina.
A continuació es declara la funció longpoll que té com a paràmetre el númeral que indica quin ha estat el últim canvi a la base de dades. Aquest s’utiliza per construir la petició que es fa a CouchDB:
var url = "http://IP_COUCHDB_SERVER:5984/notifications/_changes?include_docs=true&feed=longpoll&since="+since+"&callback=?";
La URL el que fa és demanar el següent:
- els canvis (_changes)
- incloent els documents que han canviat (include_docs=true)
- tracta la petició com a long polling (feed=longpoll)
- mostra els canvis des de la versió X (since=X)
- quan enviis els canvis fes una crida a la funció de callback definida aquí (callback=?)
- ‘?’ és substituit per jquery-jsonp per la funció anomenada ‘C’, aquest nom es pot canviar usant paràmetres en la declaració de $.jsonp() que ve a continuació
Els missatges de l’estil ‘console.log()‘ són per tenir un seguiment del que va passant a la consola de javascript del navegador.
$.jsonp() té força paràmetres possibles definits a la API, però en aquesta prova de concepte només uso ‘url’, ‘success’ i ‘error’. El primer esta clar que és, els altres dos són les funcions a cridar quan l’acció va bé o malament respectivament. Dins de la funció posem el codi referent a les accions que volem fer, per exemple, actualitzar la pàgina actual. Com que això només és una prova de concepte el que faig és mostrar missatges per consola i llestos. La part més important és fixar-se que quan la cosa ha anat bé es fa una crida a ella mateix de forma que la cosa no acabi mai. De fet quan hi ha un error es podria també fer una crida a si mateix perquè no pares de provar de llençar la petició un i altre cop, però el que he fet per provar eś que es notifiqui a la consola de javascript i prou.
Fora de la funció longpoll el que es fa és una petició JSONP per saber quina és l’últim número de seqüència de la base de dades, paràmetre necessari per entrar per primera vegada a la funció recursiva de longpoll.
Conclusions
Pot semblar tot una mica enravassat però diria que he simplificat el problema moltíssim, ja que fins ara havia estat teoritzant moltíssim sobre el tema. Fins que ahir i abans d’ahir vaig haver de posar-me a provar-ho a la pràctica per saber exactament com es podia implementar. Sota el meu punt de vista ha quedat tot força net i entenedor.
Pels que sou programadors de webs habitualment haureu tingut necessitats semblants així doncs espero que ús pugui ser tan útil com a mi, de fet, fa unes setmanes que estic treballant amb Tiny Core Linux montant un Quiet PC sobre una DOM de 512MB per usar-la de sistema de monitorització de les meves xarxes i les d’alguns clients, espero que d’aquí uns mesos pugui donar-vos més informació del projecte.
UDPTunnel – enviar els paquets UDP per sobre d’enllaços TCP
Una altre d’aquelles eines que malgrat ser petitones i rares poden servir per fer mil i una coses. Per exemple, connectar a un servidor DNS a través d’un port TCP en una xarxa on el tràfic UDP estigui tancat.
UDPTunnel és una eina molt simple d’usar i la seva sintaxis és molt autoexplicativa:
udptunnel -s TCP-port [-r] [-v] UDP-addr/UDP-port[/ttl]
udptunnel -c TCP-addr[/TCP-port] [-r] [-v] UDP-addr/UDP-port[/ttl]
és interessant fixar-se que el mateix executable pot ser usat com a servidor o com a client, així doncs ideal per construir els dos costats de l’enllaç de forma simple.
A més si ho combinem amb httptunnel podem passar per sobre de proxies de forma senzilla.
Podcast 2×04: SSH avançat
El podcast
[display_podcast]
Notes sobre el podcast
- -L: connecta per SSH a un HOST Un cop allà obre una connexió TCP a un altre HOST:PORT i obre un port TCP local que al connectar-hi ens envia al HOST:PORT anteriors, o sigui, portforwarding.
- -L [bind_address:]port:host:hostport]
- -W: connecta per SSH a un HOST un cop allà obre una connexió TCP a un altre HOST:PORT i ens retorna a la stdin/stdout el contingut d’aquest darrer enllaç TCP
- -W host:hostport
- -R publicar un port: connecta per SSH a un host i un cop allà publica un port TCP, quan un client es connecta a aquest port TCP accedeix per SSH a la màquina que ha llença l’enllaç SSH i obre un altre enllaç TCP a una altre IP:PORT.
- -R[bind_address:]port:host:hostport
- -D socks5: connecta per SSH a un HOST i després publica un port SOCKS5/TCP, és a dir, que podem connectar a aquest port local i sortir a internet a través de la IP del HOST on hem connectat per SSH
- -D [bind_address:]port
- -w tunel: connecta per SSH a un HOST i el socket que s’ha usat per fer l’enllaç SSH es connecta a dues interficies de tipus TUN, una a cada extrem del socket. Així doncs, si configurem les corresponents IPs a les interficies TUN tenim un tunel/VPN montada entre els extrems.
- -w local_tun[:remote_tun]
HPN-SSH
La web de: HPN-SSH -> especialment interessant: Dynamic Windows and None Cipher
- treballa amb mida de finestra dinàmica
- treballa sense xifrat quan un enllaç no té terminal associat, sovint usat per pas de fitxers
Les proves:
- Openssh 5.3p1 + hpn-13 (només el patch: Dynamic Windows and None Cipher)
- després d’aplicar el patch: openssh5.3-dynwindow_noneswitch.diff.gz
- modifiquem el fitxer: sshconnect2.c
<br><pre>linia: 366<br>- if (!tty_flag) /* no null on tty sessions */<br>+ if (1) /* no null on tty sessions */</pre><br>
així podem fer SSH sense xifrar només després d’haver fet el login.
exemple ampla de banada d’un SSH amb xifrat aes128-ctr, usant finestra dinàmica:
scp -v -oNoneEnabled=no -oNoneSwitch=yes fitxer root@127.0.0.1:/tmp/ssh
o
ssh -v -oNoneEnabled=no -oNoneSwitch=yes root@127.0.0.1 "dd if=/dev/zero"|pv > /dev/null
velocitat de transferència: <strong>13.7MB/s</strong>
- debug ciphers, una única negociació de ciphers:
debug1: AUTH STATE IS 0
debug1: REQUESTED ENC.NAME is '<strong>aes128-ctr</strong>'
debug1: kex: server-><strong>client</strong> aes128-ctr hmac-md5 none
debug1: REQUESTED ENC.NAME is '<strong>aes128-ctr</strong>'
debug1: kex: client-><strong>server</strong> aes128-ctr hmac-md5 none
exemple sense xifrat, usant finestra dinàmica:
scp -v -oNoneEnabled=yes -oNoneSwitch=yes fitxer root@127.0.0.1:/tmp/ssh
o
ssh -v -oNoneEnabled=yes -oNoneSwitch=yes root@127.0.0.1 "dd if=/dev/zero"|pv > /dev/null
velocitat de transferència: <strong>37.4MB/s</strong>
- abans del pass de login:
debug1: <strong>AUTH</strong> STATE IS <strong>0</strong>
debug1: REQUESTED ENC.NAME is '<strong>aes128-ctr</strong>'
debug1: kex: server-><strong>client</strong> aes128-ctr hmac-md5 none
debug1: REQUESTED ENC.NAME is '<strong>aes128-ctr</strong>'
debug1: kex: client-><strong>server</strong> aes128-ctr hmac-md5 none
- després d’autenticar-se:
debug1: <strong>AUTH</strong> STATE IS <strong>1</strong>
debug1: REQUESTED ENC.NAME is '<strong>none</strong>'
debug1: Requesting NONE. Authflag is 1
debug1: None requested post authentication.
debug1: kex: server-><strong>client</strong> none hmac-md5 none
debug1: REQUESTED ENC.NAME is '<strong>none</strong>'
debug1: Requesting NONE. Authflag is 1
debug1: None requested post authentication.
debug1: kex: client-><strong>server</strong> none hmac-md5 none
Podcast 2×03: eines per jugar amb SOCKS5
Finalment l’última entrega de la trilogia de podcasts sobre SOCKS. Com indica el títol i podeu veure amb els links aquest parla d’eines per montar servidors SOCKS i wrappers per montar clients SOCKS5.
El podcast:
[display_podcast]
Referències:
- Apunts per fer el podcast: fitxer .txt amb les meves notes per fer el podcast, mig en català i anglès.
- Servidors:
- Clients/Wrappers/Proxifiers:
- tsocks
- csocks
- connect-proxy
- proxychains
- SocksiPy (python)
- ICP (Internet Cache Protocol)
Podcast 2×02: SOCKS5 Bytestreams (XEP-0065)
La segona part sobre la trilogia de SOCKS5.
El podcast:
[display_podcast]
Exemples extrets del XEP-0065:
Example 1. Initiator Sends Service Discovery Request to Target
<iq type='get' from='initiator@example.com/foo' to='target@example.org/bar' id='hello'> <query xmlns='http://jabber.org/protocol/disco#info'/> </iq>
Example 2. Target Replies to Service Discovery Request
<iq type='result' from='target@example.org/bar' to='initiator@example.com/foo' id='hello'> <query xmlns='http://jabber.org/protocol/disco#info'> <identity category='proxy' type='bytestreams' name='SOCKS5 Bytestreams Service'/> <feature var='http://jabber.org/protocol/bytestreams'/> </query> </iq>
Example 3. Initiator Sends Service Discovery Request to Server
<iq type='get' from='initiator@example.com/foo' to='example.com' id='server_items'> <query xmlns='http://jabber.org/protocol/disco#items'/> </iq>
Example 4. Server Replies to Service Discovery Request
<iq type='result' from='example.com' to='initiator@example.com/foo' id='server_items'> <query xmlns='http://jabber.org/protocol/disco#items'> <item jid='streamhostproxy.example.net' name='Bytestreams Proxy'/> </query> </iq>
Example 5. Initiator Sends Service Discovery Request to Proxy
<iq type='get' from='initiator@example.com/foo' to='streamhostproxy.example.net' id='proxy_info'> <query xmlns='http://jabber.org/protocol/disco#info'/> </iq>
Example 6. Server Replies to Service Discovery Request
<iq type='result' from='streamhostproxy.example.net' to='initiator@example.com/foo' id='proxy_info'> <query xmlns='http://jabber.org/protocol/disco#info'> <identity category='proxy' type='bytestreams' name='SOCKS5 Bytestreams Service'/> <feature var='http://jabber.org/protocol/bytestreams'/> </query> </iq>
Example 7. Initiator Requests Network Address from Proxy
<iq type='get' from='initiator@example.com/foo' to='streamhostproxy.example.net' id='discover'> <query xmlns='http://jabber.org/protocol/bytestreams' sid='vxf9n471bn46'/> </iq>
Example 8. Proxy Informs Initiator of Network Address
<iq type='result' from='streamhostproxy.example.net' to='initiator@example.com/foo' id='discover'> <query xmlns='http://jabber.org/protocol/bytestreams'> sid='vxf9n471bn46'> <streamhost jid='streamhostproxy.example.net' host='24.24.24.1' p zeroconf='_jabber.bytestreams'/> </query> </iq>
Example 9. Proxy Returns Error to Initiator
<iq type='error' from='initiator@example.com/foo' to='streamhostproxy.example.net' id='discover'> <query xmlns='http://jabber.org/protocol/bytestreams' sid='vxf9n471bn46'/> <error code='403' type='auth'> <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq>
Example 10. Proxy Returns Error to Initiator
<iq type='error' from='initiator@example.com/foo' to='streamhostproxy.example.net' id='discover'> <query xmlns='http://jabber.org/protocol/bytestreams' sid='vxf9n471bn46'/> <error code='405' type='cancel'> <not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq>
Example 11. Initiation of Interaction
<iq type='set' from='initiator@example.com/foo' to='target@example.org/bar' id='initiate'> <query xmlns='http://jabber.org/protocol/bytestreams' sid='vxf9n471bn46' mode='tcp'> <streamhost jid='initiator@example.com/foo' host='192.168.4.1' port='5086'/> <streamhost jid='streamhostproxy.example.net' host='24.24.24.1' zeroconf='_jabber.bytestreams'/> </query> </iq>
Example 12. Target Refuses Bytestream
<iq type='error' from='target@example.org/bar' to='initiator@example.com/foo' id='initiate'> <error code='406' type='auth'> <not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq>
Example 13. Target Is Unable to Connect to Any StreamHost and Wishes to End Transaction
<iq type='error' from='target@example.org/bar' to='initiator@example.com/foo' id='initiate'> <error code='404' type='cancel'> <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq>
Example 16. Target Notifies Initiator of Connection
<iq type='result' from='target@example.org/bar' to='initiator@example.com/foo' id='initiate'> <query xmlns='http://jabber.org/protocol/bytestreams' sid='vxf9n471bn46'> <streamhost-used jid='streamhostproxy.example.net'/> </query> </iq>
Example 19. Initiator Requests Activation of Bytestream
<iq type='set' from='initiator@example.com/foo' to='streamhostproxy.example.net' id='activate'> <query xmlns='http://jabber.org/protocol/bytestreams' sid='vxf9n471bn46'> <activate>target@example.org/bar</activate> </query> </iq>
Example 20. Proxy Informs Initiator of Activation
<iq type='result' from='streamhostproxy.example.net' to='initiator@example.com/foo' id='activate'/>
Referències:
- Apunts per fer el podcast: fitxer .txt amb la llista de coses que volia comentar al podcast és una barreja de català, castellà i anglès.
- RFC i XEPs:
- RFC1928: SOCKS Protocol v5
- XEP-0065: SOCKS5 Bytestream
- XEP-0030: Service Discovery
- Extencions del XMPP: tots els XEPs
from=’initiator@example.com/foo’
to=’target@example.org/bar’
id=’hello’>
<query xmlns=’http://jabber.org/protocol/disco#info’/>
</iq>