Usare i socket in flash è stato per molto tempo fin troppo facile, quasi intuitivo e questa condizione ha fornito ai soliti malintenzionati la possibilità di creare molti problemi (per esempio caricamento di informazioni senza che il navigatore se ne accorgesse e “rubandole” da altri siti, oppure effettuare connessioni inopportune e di massa verso server legittimi). Per evitare questo dalla versione 9.0.124.0 (e successive quindi anche la 10.x attualmente in uso) per poter effettuare connessione remote è indispensabile che il server a cui si desidera collegarsi fornisca una “flashpolicy”, ovvero un file XML dove sono contenute informazioni relativamente a quali server si possono collegare e con quale frequenza/condizioni a quello dove la policy è servita.

Ad ogni tentativo di accesso remoto il “flash player” effettua una richiesta al server di destinazione usando prima di tutto la porta TCP 843 e poi un eventuale altra porta specificata da chi ha creato l’applicativo in flash. In caso nessuna flashpolicy venga trovata allora la connessione non è consentita, in caso contrario il file XML viene analizzato e l’accesso è effettuato solo se esplicitamente consentito. Il file XML ha un formato molto simile a questo :

<?xml version="1.0"?>

<!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd">

<cross-domain-policy>

<site-control permitted-cross-domain-policies="master-only"/>

<allow-access-from domain="*" to-ports="4000" />

</cross-domain-policy>

Per maggiori descrizioni sulla sintassi del file è sufficiente appoggiarsi al sito dell’Adobe, ai fini di questo articolo basti sapere che comunque questo specifico file segnala al flash player di accettare una connessione TCP sulla porta 4000 proveniente da un qualunque indirizzo IP. Il vero problema di gestire questo file è disporre di un software che fornisca la policy in risposta ad una specifica richiesta. Nelle mie ricerche ho trovato pochi esempi compilati sommariamente e quindi ho preferito disporne  uno in autonomia usando il linguaggio C per garantire la massima flessibilità e una buona portabilità:

/*
----------------------------------------
MUDflash_policy               02.02.2010
----------------------------------------
Server in ascolto su una porta specifica
che rimane in attesa di connessioni per
inviare una stringa di dati ad un client
richiedente.
----------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define VERSIONE    "0.1"
#define SERVER_PORT 4003
int main(int argc, char *argv[]) {
struct sockaddr_in  srv_addr;                         // indirizzo del server
struct sockaddr_in  client_addr;                      // indirizzo del client
int                 client_len = sizeof(client_addr); // dimensione dell'indirizzo del client
int                 listen_sd;                        // descrittore in ascolto     - canale pubblico
int                 accept_sd;                        // descrittore in connessione - canale privato
int                 r = -1;                           // valore di ritorno da funzione
char                buffer[1024] = "";                // buffer in ricezione e stringa da spedire
int                 n = 0;                            // numero di caratteri da spedire al client
/* Visualizza il messaggio di presentazione */
printf("\r\n");
printf("MUDflash_policy, versione %s\r\n", VERSIONE);
printf("-----------------------------\r\n");
/* Crea un sd in ascolto */
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sd < 0) {
perror("MUDflash_policy - socket()");
exit(-1);
}
/* Collega il socket alla porta specificata */
memset(&srv_addr, 0, sizeof(srv_addr));
srv_addr.sin_family       = AF_INET;
srv_addr.sin_addr.s_addr  = htonl(INADDR_ANY);
srv_addr.sin_port         = htons(SERVER_PORT);
r = bind(listen_sd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
if (r < 0) {
perror("MUDflash_policy - bind()");
close(listen_sd);
exit(-1);
}
/* Apri il canale pubblico */
r = listen(listen_sd, 5);
if (r < 0) {
perror("MUDflash_policy - listen()");
close(listen_sd);
exit(-1);
}
printf("Server avviato, in attesa di connesioni sulla porta %d.\n", SERVER_PORT);
/* Avvia l'ascolto per connessioni entranti */
for (; ;)  {
accept_sd = accept(listen_sd,(struct sockaddr*) &client_addr, &client_len);
if (accept_sd < 0) {
perror("MUDflash_policy - accept()");
close(listen_sd);
exit(-1);
}
/* Un client si e' connesso (accept sbloccata) */
printf("*** Connessione di un client avvenuta ***\r\n");
/* Ricevi un messaggio dal client */
sprintf(buffer, "");  // svuota il buffer prima che si accodino msg di connessioni precedenti e degeneri in overflow...
r = recv(accept_sd, buffer, sizeof(buffer), 0);
if (r <= 0) {
perror("MUDflash_policy - recv()");
close(listen_sd);
close(accept_sd);
exit(-1);
}
printf("Messaggio ricevuto: \"%s\".\r\n", buffer);
/* Invia la policy al client */
strcpy(buffer, "<?xml version='1.0'?>\n<!DOCTYPE cross-domain-policy SYSTEM");
strcat(buffer, "'/xml/dtds/cross-domain-policy.dtd'><cross-domain-policy>\n");
strcat(buffer, "<site-control permitted-cross-domain-policies='all'/>\n");
strcat(buffer, "<allow-access-from domain='*' to-ports='4000' />\n");
strcat(buffer, "</cross-domain-policy>\n");
n = strlen(buffer);
r = send(accept_sd, buffer, n, 0);
if (r <= 0) {
perror("MUDflash_policy - send()");
close(listen_sd);
close(accept_sd);
exit(-1);
}
printf("Invio della Policy al client...OK\r\n");
/* chiudi il canale privato */
close(accept_sd);
printf("Chiusura della connessione con il client.\r\n");
}
/* chiudi il canale pubblico */
close(listen_sd);
}
/* EoF */
Cambiando pochi parametri quali il contenuto della flashpolicy (vedere le strcat utilizzate per preparare il buffer di scrittura) e la costante SERVER_PORT, dove l’applicativo si mette in ascolto, è possibile approntare una flashpolicy personalizzata che consenta di utilizzare liberamente i socket. Sicuramente a questo programma è possibile apportare migliorie quali per esempio la gestione della flashpolicy in una “costante” piuttosto che in un buffer che ogni volta viene compilato o ancora l’uso del comando fork per meglio gestire le accept e garantire maggiormente la possibilità di accettare più connessioni simultanee.
Come sempre spero che il mio lavoro vi sia utile!