Como executar um script BASH em resposta a um evento de rede?

2

Eu tenho um pequeno script BASH que gostaria de usar em alguns Macs (um mix de 10.8.5 e 10.9.4). Eu gostaria de acionar o script sempre que meu mac tenta se conectar a outro através de uma porta TCP específica. Os endereços IP de ambos os computadores são conhecidos, e eu posso ver o tráfego (conexão na porta 6472) quando assisto via nettop ou console.

O que não consegui encontrar - e talvez não esteja pesquisando corretamente - é uma ferramenta que será executada em segundo plano e aguardará a solicitação de conexão e, em seguida, executará um executável quando ele ocorrer. Eu suponho que eu poderia cozinhar um, mas isso parece ser um problema que outros já resolveram. Qualquer direção para uma solução existente seria muito bem-vinda.

Obrigado! Mike

    
por Mike 23.09.2014 / 03:00

3 respostas

0

Que tal executar algo assim em segundo plano, usando o tcpdump com o filtro certo e ativando seu script toda vez Corresponde ?

tcpdump -l -i eth0 'dst host other_host and dst port 6472 and tcp[tcpflags] = tcp-syn' 2>/dev/null | while read f ; do your_script; done

substitua eth0 pela sua interface de rede, other_host pelo endereço IP da outra máquina

Se você não quer uma janela de terminal por aí, você pode fazer disso um script bash e executá-lo dentro de uma sessão tela .

    
por 08.10.2014 / 02:05
0

Outra solução alternativa e possivelmente mais simples para a solução @ultrasawblade pode ser executar knockd . - Parece que há uma versão disponível para Mac.

    
por 08.10.2014 / 02:28
0

Provavelmente, a abordagem mais versátil e personalizada para concluir sua missão é analisar dtrace .

Use um soquete genérico ou um provedor tcp e execute o script no modo destrutivo para chamar system() do kernel ou use o Rastreamento de Limite de Função (FBT) como seu provedor. Este último fará com que o seu script dependa da versão do OSX.

Brincando um pouco, eu criei algo que deveria lhe dar força suficiente para a sua solução final usando um provedor de soquete (por isso deve funcionar em ambas as suas máquinas MacOSX):

#!/usr/sbin/dtrace -s

#pragma D option quiet
#pragma D option switchrate=10hz
#pragma D option destructive 

/* AF_INET{6} are unknown to dtrace, so replace with numbers */
inline int af_inet  =  2; /* AF_INET  */
inline int af_inet6 = 30; /* AF_INET6 */
inline const string procname = "nc";

dtrace:::BEGIN
{
    /* Add translations as desired from /usr/include/sys/errno.h */
    err[0]            = "Success";
    err[EINTR]        = "Interrupted syscall";
    err[EIO]          = "I/O error";
    err[EACCES]       = "Permission denied";
    err[ENETDOWN]     = "Network is down";
    err[ENETUNREACH]  = "Network unreachable";
    err[ECONNRESET]   = "Connection reset";
    err[ECONNREFUSED] = "Connection refused";
    err[ETIMEDOUT]    = "Timed out";
    err[EHOSTDOWN]    = "Host down";
    err[EHOSTUNREACH] = "No route to host";
    err[EINPROGRESS]  = "In progress";
    err[EADDRNOTAVAIL] = "Can't assign requested address";

    printf("%-6s %-20s %-8s %-21s %-21s %-8s %s\n", 
        "PID", "PROCNAME", "FAMILY", "S_ADDR:S_PORT", "D_ADDR:D_PORT", 
        "LAT(us)", "RESULT");
}

/*  MacOSX connectx() syscall:

    connectx(arg0:int s, arg1:struct sockaddr *src, arg2:socklen_t srclen, 
                         arg3:struct sockaddr *dsts, arg4:socklen_t dstlen, 
                         arg5:uint32_t ifscope, arg6: associd_t aid, 
                         arg7:connid_t *cid);
*/

syscall::connectx:entry
{
    this->s = (struct sockaddr_in *) copyin(arg3, sizeof(struct sockaddr)); 
    this->f = this->s->sin_family;
} 

syscall::connectx:entry 
/ this->f == af_inet && execname == procname / 
{ 
    this->s = (struct sockaddr_in *) copyin(arg1, sizeof(struct sockaddr)); 
    self->address = inet_ntop(this->f, (void *) &this->s->sin_addr);
    self->port = ntohs(this->s->sin_port);
    self->s_addr = strjoin(strjoin(self->address, ":"), lltostr(self->port));

    this->d = (struct sockaddr_in *) copyin(arg3, sizeof(struct sockaddr)); 
    self->address = inet_ntop(this->f, (void *) &this->d->sin_addr);
    self->port = ntohs(this->d->sin_port);  
    self->d_addr = strjoin(strjoin(self->address, ":"), lltostr(self->port));

    self->ts = timestamp; 
}

syscall::connectx:entry
/ this->f == af_inet6 && execname == procname /
{
    this->s6 = (struct sockaddr_in6 *) copyin(arg1, sizeof(struct sockaddr_in6));
    self->port = ntohs(this->s6->sin6_port);
    self->address = inet_ntop(this->f, (void *) &this->s6->sin6_addr);
    self->s_addr = strjoin(strjoin(self->address, ":"), lltostr(self->port));

    this->d6 = (struct sockaddr_in6 *) copyin(arg3, sizeof(struct sockaddr_in6));
    self->port = ntohs(this->d6->sin6_port);
    self->address = inet_ntop(this->f, (void *) &this->d6->sin6_addr);
    self->d_addr = strjoin(strjoin(self->address, ":"), lltostr(self->port));

    self->ts = timestamp;
}

syscall::connectx:return 
/ self->ts / 
{ 
    this->delta = (timestamp - self->ts) / 1000; 
    this->errstr = err[errno] != NULL ? err[errno] : lltostr(errno);

    /* Basically anything can be called here */
    system("date");
    printf("%-6d %-20s %-8d %-21s %-21s %-8d %s\n", 
        pid, execname, this->f, self->s_addr, self->d_addr,
        this->delta, this->errstr); 

    self->family = 0; 
    self->ts = 0; 
}

Salve-o em um arquivo (digamos ./socket_connect_mac_simple.d ) e, em seguida, chame o código da seguinte forma:

$ sudo ./socket_connect_mac_simple.d

Abra outro terminal e inicie nc como um servidor:

$ nc -4 -k -l 127.0.0.1 6472 > /dev/null

E em outro terminal, conecte-se a ele:

$ while :; do nc -4 -s 192.168.0.19 127.0.0.1 6472 < /usr/bin/true; sleep 0.5; done

Sua saída deve parecer algo nos seguintes termos:

$ sudo ./socket_connect_mac_simple.d
PID    PROCNAME         FAMILY   S_ADDR:S_PORT         D_ADDR:D_PORT         LAT(us)  RESULT
45823  nc               2        192.168.0.19:0        127.0.0.1:6472        240      Success
45825  nc               2        192.168.0.19:0        127.0.0.1:6472        234      Success
45827  nc               2        192.168.0.19:0        127.0.0.1:6472        236      Success
45829  nc               2        192.168.0.19:0        127.0.0.1:6472        240      Success
45831  nc               2        192.168.0.19:0        127.0.0.1:6472        241      Success
45833  nc               2        192.168.0.19:0        127.0.0.1:6472        238      Success
45835  nc               2        192.168.0.19:0        127.0.0.1:6472        234      Success
45837  nc               2        192.168.0.19:0        127.0.0.1:6472        241      Success
45839  nc               2        192.168.0.19:0        127.0.0.1:6472        236      Success
45841  nc               2        192.168.0.19:0        127.0.0.1:6472        237      Success

Obviamente, você estará substituindo nc com sua lista de daemon na porta 6472 e também terá que chamar seu script bash onde eu coloquei o fragmento de código system("date") . Além disso, deve funcionar apenas como você descreveu.

Assegure-se de ler a documentação sobre o modo destrutivo chamada dtrace system() : Chamadas no Modo Destrutivo dentro do DTrace

    
por 28.12.2014 / 05:53