Diferença entre / dev / udp e netcat

4

Eu tenho um servidor syslog escutando em localhost: 514 como UDP e gostaria de escrever mensagens para ele nessa porta. (Usando o Ubuntu 14.04)

Se eu executar um desses comandos, do bash ele imprime a data a cada 2 segundos para o syslog

# Using netcat
while true; do sleep 2; date; done | nc -u localhost 514

# Using /dev/udp
while true; do sleep 2; date; done > /dev/udp/localhost/514

Agora, apenas para testar as coisas, eu mato o servidor syslog e o inicio alguns segundos depois.

Enquanto o processo syslog está inativo, o comando / dev / udp a cada 2 segundos imprime isso no console, portanto ele reconhece que não há localhost: 514 para ele gravar. Quando o syslog estiver de volta, essas mensagens de conexão recusada serão interrompidas e a nova data será gravada no syslog. Isso é como esperado.

date: write error: Connection refused

Mas o comando netcat não faz isso. Enquanto o processo syslog está inativo, ele não imprime qualquer saída para o console. E quando o syslog está de volta, ele não continua gravando a data no syslog.

Por que o netcat não continua gravando no localhost: 514 quando o syslog é reiniciado? Como posso fazer com que o netcat se comporte como o / dev / udp faz neste exemplo?

    
por user779159 29.07.2014 / 13:58

1 resposta

6

Isso parece ser um bug em nc . O comando nc usa a chamada do sistema poll para aguardar até que a entrada seja recebida de stdin ou do soquete.

Quando um pacote UDP foi enviado para uma porta UDP fechada no terminal de recebimento, uma mensagem de erro é enviada de volta. A chamada poll retornará esse status para o comando nc , mas nc na verdade não processará o erro. Em vez disso, nc volta a chamar a chamada do sistema poll novamente, que retorna imediatamente devido ao erro que ainda está sendo enfileirado no soquete.

Isso poderia ter sido um loop infinito, onde nc consumiria todo o tempo de CPU que poderia fazer sem ser útil.

No entanto, dura apenas até a próxima mensagem ser recebida em stdin . Neste ponto, poll retorna os dois status para nc , que processa os dados de stdin . Agora nc tentará gravar os dados de stdin no soquete. A tentativa de gravar no soquete entregará o erro na fila para nc . A mensagem de erro de gravação fará com que nc termine.

Isso deixa você com um cano quebrado (isto é, um cano com um gravador, mas nenhum leitor). Qualquer tentativa de gravar no pipe acionará um sinal SIGPIPE e se o processo não for eliminado pelo SIGPIPE de um erro da chamada de gravação.

date não está processando SIGPIPE , então date é eliminado. Portanto, o loop continua, mas sempre que date é eliminado ao tentar gravar no canal em que o leitor está ausente há muito tempo.

O que pode ser feito

Embora o nc de loop na chamada do sistema poll sem entregar o erro seja definitivamente um bug, corrigir esse bug não seria necessariamente suficiente para atender às suas necessidades. Simplesmente terminar assim que o erro for retornado de poll pode ser considerado o bug correto para nc . Poderíamos imaginar um recurso adicional, em que nc poderia ser instruído a continuar após um erro se receber uma sinalização específica.

Mas você poderia contornar o problema simplesmente reiniciando o nc em um loop como este:

while sleep 1 ; do date ; done | while true ; do nc -u localhost 514 ; done

O bug que causa uso excessivo da CPU periodicamente em nc ainda estaria lá. Além disso, a combinação desse bug e a solução alternativa podem fazer com que a primeira mensagem após a porta de destino seja reaberta seja perdida.

    
por 29.07.2014 / 14:31