Blog der Heimetli Software AG

Ein Programm ausführen wenn ein UDP-Paket eintrifft

Das folgende Programm wartet auf ein UDP-Paket an einem angegebenen Port. Sobald dort ein Paket eintrifft, wird ein Script oder Programm ausgeführt.

Aufruf

$ ./udpexecute 7777 /bin/echo works fine!
udpexecute V1.00
works fine!
works fine!
  • 7777 ist das Port
  • /bin/echo wird ausgeführt wenn ein Paket eintrifft
  • works ist das erste Argument für /bin/echo
  • fine! ist das zweite Argument für /bin/echo

Das angegebene Programm muss entweder ein ELF oder ein Script mit einem Shebang sein. echo allein funktioniert nicht, weil es ein Shell-Builtin ist.

Alle Argumente werden unverändert weitergereicht.

Source

Der Code sollte weitgehend selbsterklärend sein für Leute die C kennen, und schon einmal auf Linux entwickelt haben.

/******************************************************************************/
/*                                                                            */
/*                                                       FILE: udpexecute.cpp */
/*                                                                            */
/*  Executes a program when a UDP packet is received                          */
/*  ================================================                          */
/*                                                                            */
/*  V1.00   24-APR-2018   Te                                                  */
/*                                                                            */
/******************************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/****************************/
 int CreateSocket( int port )
/****************************/

{
    // Create a socket
    int sock = socket( AF_INET, SOCK_DGRAM, 0 ) ;

    if( sock == -1 )
    {
       fprintf( stderr, "CreateSocket: socket failed\n" ) ;
       return -1 ;
    }

    // Bind it to the local address
    struct sockaddr_in address ;

    memset( &address, 0, sizeof(address) ) ;

    address.sin_family      = AF_INET ;
    address.sin_addr.s_addr = htonl( INADDR_ANY ) ;
    address.sin_port        = htons( port ) ;

    if( bind(sock,(struct sockaddr *)&address,sizeof(address)) == -1 )
    {
       fprintf( stderr, "CreateSocket: bind failed\n" ) ;
       close( sock ) ;
       return -1 ;
    }

    return sock ;
}

/**********************************/
 int main( int argc, char *argv[] )
/**********************************/

{
   fprintf( stderr, "udpexecute V1.00\n" ) ;

   if( argc < 3 )
   {
      fprintf( stderr, "usage: %s port program [args]\n", argv[0] ) ;
      return 1 ;
   }

   int socket = CreateSocket( atoi(argv[1]) ) ;

   if( socket == -1 )
   {
      fprintf( stderr, "error: can't create socket\n" ) ;
      return 2 ;
   }

   struct sockaddr_in address ;
   char   line[256] ;
   int    status ;
   int    size ;

   for( ;; )
   {
       socklen_t length = sizeof( address ) ;
       size = recvfrom( socket, line, sizeof(line), 0, (struct sockaddr *)&address, &length ) ;

       if( size < 1 )
       {
          fprintf( stderr, "error: recvfrom failed\n" ) ;
          break ;
       }

       pid_t pid = fork() ;

       switch( pid )
       {
	  case -1: fprintf( stderr, "fork failed\n" ) ;
		   break ;

	  case  0: execv( argv[2], argv + 2 ) ;
		   fprintf( stderr, "exec failed: %s\n", strerror(errno) ) ;
		   break ;

          default: wait( &status ) ;
		   break ;
       }
   }

   close( socket ) ;

   return 0 ;
}

Build

Builden ist einfach:

g++ -o udpexecute udpexecute.cpp

Download

Source von udpexecute

Update vom 2. August 2020

Auf Anregung eines Users habe ich die Argumente durch den Inhalt des UDP-Pakets ersetzt. Das hat mich aber nicht so recht überzeugt, und deshalb gibt es jetzt eine Version mit Argumenten und zusätzlich dem Inhalt des Frames. Im gleichen Zug ist auch die IP-Adresse des Absenders hinzugekommen.

/******************************************************************************/
/*                                                                            */
/*                                                       FILE: udpexecute.cpp */
/*                                                                            */
/*  Executes a program when a UDP packet is received                          */
/*  ================================================                          */
/*                                                                            */
/*  V1.00   24-APR-2018   Te                                                  */
/*  V1.10   26-JUL-2020   Te   Replaced arguments with content of UDP packet  */
/*  V1.20   02-AUG-2020   Te   Added content and IP address to arguments      */
/*                                                                            */
/******************************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>

/****************************/
 int CreateSocket( int port )
/****************************/

{
    // Create a socket
    int sock = socket( AF_INET, SOCK_DGRAM, 0 ) ;

    if( sock == -1 )
    {
       fprintf( stderr, "CreateSocket: socket failed\n" ) ;
       return -1 ;
    }

    // Bind it to the local address
    struct sockaddr_in address ;

    memset( &address, 0, sizeof(address) ) ;

    address.sin_family      = AF_INET ;
    address.sin_addr.s_addr = htonl( INADDR_ANY ) ;
    address.sin_port        = htons( port ) ;

    if( bind(sock,(struct sockaddr *)&address,sizeof(address)) == -1 )
    {
       fprintf( stderr, "CreateSocket: bind failed\n" ) ;
       close( sock ) ;
       return -1 ;
    }

    return sock ;
}

/****************************************************************/
 void Execute( int argc, char *argv[], char *line, in_addr addr )
/****************************************************************/

{
   int   index = 0 ;
   char *args[argc+1] ;

   for( int i = 2; i < argc; i++ )
      args[index++] = argv[i] ;

   args[index++] = line ;
   args[index++] = inet_ntoa( addr ) ;
   args[index]   = NULL ;
   
   execv( args[0], args ) ;

   fprintf( stderr, "exec failed: %s\n", strerror(errno) ) ;
}

/**********************************/
 int main( int argc, char *argv[] )
/**********************************/

{
   fprintf( stderr, "udpexecute V1.20\n" ) ;

   if( argc < 3 )
   {
      fprintf( stderr, "usage: %s port program [args]\n", argv[0] ) ;
      return 1 ;
   }

   int socket = CreateSocket( atoi(argv[1]) ) ;

   if( socket == -1 )
   {
      fprintf( stderr, "error: can't create socket\n" ) ;
      return 2 ;
   }

   struct sockaddr_in address ;
   char   line[256] ;
   int    status ;
   int    size ;

   for( ;; )
   {
       socklen_t length = sizeof( address ) ;
       size = recvfrom( socket, line, sizeof(line)-1, 0, (struct sockaddr *)&address, &length ) ;

       if( size < 1 )
       {
          fprintf( stderr, "error: recvfrom failed\n" ) ;
          break ;
       }

       line[size] = '\0' ;
       pid_t  pid = fork() ;

       switch( pid )
       {
	  case -1: fprintf( stderr, "fork failed\n" ) ;
		   break ;

	  case  0: Execute( argc, argv, line, address.sin_addr ) ;
		   break ;

          default: wait( &status ) ;
		   break ;
       }
   }

   close( socket ) ;

   return 0 ;
}

Builden und Ausführen geht genau gleich wie bisher, aber das Programm bekommt zwei zusätzliche Argumente:

$ ./udpexecute 7777 /bin/echo hello
udpexecute V1.20
hello world 192.168.1.60