2016-02-01 24 views
5

LwIPスタック(軽量IP)を実行している組み込みシステム上で実行されていたlinuxでサービスを再作成する必要があります。複数のインターフェイスでUDPブロードキャストを送受信するサービスを作成する方法

サービスでは、UDPブロードキャストをINADDR_BROADCAST(255.255.255.255)に使用して、同じ物理サブネット上のデバイスを検索および設定しています。 "スキャン"と、このサービス応答を実行するすべてのデバイスに完全なネットワーク設定(すべてのNIC、すべてのMACとIP)を送信します。 ユーザはこれらのデバイスのリストを取得し、(既存のプロトコルを使用して)IP設定を変更することができます。
[はい、私は人々がこのためにDHCPを使用して知っているが、我々はここに産業部門の話をしているとプロトコル/サービスがすでに存在しているので、私は選択肢がないが、互換性のある何かを実装する]デバイスは、いくつかを持っているので

をNICでは、このブロードキャストを受信し、どのNICがそれを受信したかを知り、そのNICを介して応答を送信する必要があります。 サービスは、特定のNIC上のソケットを開かないように構成することもできます。

LwIPスタックはLinuxスタックほど洗練されていないため、IPにバインドされたソケットはまだすべてのパケットをINADDR_BROADCASTに受け取ります。したがって、これを実装するのはかなり簡単です。 Linuxの

、私はこれを行うには、いくつかのオプションがあり考え出し:SO_BROADCASTSO_BINDTODEVICE

  • 各NICのためのオープン個々のソケットを、私はINADDR_ANYにそれらをbind()と放送を受信することができます。そのソケットを介して返信を送信すると、Linuxのルーティングは無視され、目的のNIC経由で送信されます。
    しかし:私はrootとして実行しないようにサービスを希望...
  • は、結合、(簡単にパケットがに到着したNIC知っている可能性がIP_PKTINFO付き)シングルINADDR_ANYバインドされたソケットをお持ちのNICごとに1つのソケットを持っています有効な住所にSO_BROADCASTと送信し、それらを介して返信を送信します。私がこのようにすれば、私はrecv()を呼び出すことはないので、送信ソケットが何も受信できないことを確認したいと思っています。
    おそらくSO_RCVBUFSIZE = 0で十分でしょうか?

これを実装する正しい方法は何でしょうか?

+0

単純に適切な分析をしなくても、非常に答えにくいです。あなたの分析を完了するために単純なmokeupを作成してみてください。 (私は産業部門ではこのサービスを実行していることは知らないが、私はセキュリティについて怪しいです...) – rom1nux

+0

このプロトコルは初期設定用で、システムが "実行"モードになったらIP設定を変更することはできません。 – TabascoEye

+0

私は静かな最小値では 'SO_RCVBUFSIZE = 0'が役に立たないと思います。さらなる読み込みを無効にするには 'shutdown(sockfd、SHUT_RD)'を使うことができますが、プログラムを正しく書くだけです:) –

答えて

2

CAP_NET_RAW(およびポート1024以下の場合はCAP_NET_BIND_SERVICE)でバイナリをインストールできます。ルートとしてsetcap 'cap_net_raw=ep' yourdaemon IPの場合、SO_BROADCASTは機能を必要としません(特に、CAP_NET_BROADCASTはIPには使用されません)。

(必要な正確な機能については、検証のために例えばnet/core/sock.c:sock_setbindtodevice()net/core/sock.c:sock_setsockopt()、およびLinuxカーネルのソースでinclude/net/sock.h:sock_set_flag()参照。)

しかし、デーモンは通常rootとして開始されます。ここでは、プロセスのユーザーIDを変更して(特権を削除するため)、clears the effective capabilitiesも同様です。しかし、私もサービスを制限された権限で実行することを好む。私は2つの基本的な方法のいずれかを選択なる

  1. は、デーモンがルートによって、またはCAP_NET_RAW(および任意CAP_NET_BIND_SERVICE)機能を使用して実行されることを必要とします。

    使用prctl()setgroups()又はinitgroups()setresuid()setresgid()、及びlibcapから、cap_init()cap_set_flag()、及びcap_set_proc()専用ユーザおよびグループへの切り替えが、唯一CAP_NET_RAW(および任意CAP_NET_BIND_SERVICE)機能と、それらを保持することによって権限をドロップします。

    これにより、デーモンは、 HUP信号は、インターフェイスを列挙し、独自の構成ファイルを読み込んで新しいインターフェイス用のソケットを開くために必要な特権を持つため、完全に再起動する必要はありません。

  2. すべての必要なソケットを開き、権限を削除し、実際のデーモンを実行する特権の「ローダー」を使用します。

    デーモンは、ソケットやインターフェイスの詳細をコマンドラインパラメータとして、または標準入力経由で取得する必要があります。デーモンは完全に権限がありません。

    残念ながら、新しいインターフェイスが開かれたり、設定が変更されたりすると、デーモンは終了以外の多くのことを行うことができません。 (権限はすでに削除されているので、それも、特権ローダーを実行することはできません。)

最初のアプローチは、実際に実装するのがより一般的、かつ簡単です。特に、デーモンがrootによってのみ実行されるはずです。 (デーモンは、必要な機能を備えているが一般的にはroot権限ではないので、設定の変更に対応できることを忘れないでください)私は信頼できない「ブラックボックス」バイナリの第2のアプローチしか使用していません。


ここにいくつかのコード例を示します。

privileges.h

#define _GNU_SOURCE 
#define _BSD_SOURCE 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/capability.h> 
#include <sys/prctl.h> 
#include <errno.h> 
#include <pwd.h> 
#include <grp.h> 
#include "privileges.h" 

/* Only three NEED_CAP_ constants defined. */ 
#define MAX_CAPABILITIES 3 

static int permit_effective(cap_t caps, const unsigned int capabilities) 
{ 
    cap_value_t value[MAX_CAPABILITIES]; 
    int   values = 0; 

    if (capabilities & NEED_CAP_NET_ADMIN) 
     value[values++] = CAP_NET_ADMIN; 

    if (capabilities & NEED_CAP_NET_BIND_SERVICE) 
     value[values++] = CAP_NET_BIND_SERVICE; 

    if (capabilities & NEED_CAP_NET_RAW) 
     value[values++] = CAP_NET_RAW; 

    if (values < 1) 
     return 0; 

    if (cap_set_flag(caps, CAP_PERMITTED, values, value, CAP_SET) == -1) 
     return errno; 
    if (cap_set_flag(caps, CAP_EFFECTIVE, values, value, CAP_SET) == -1) 
     return errno; 

    return 0; 
} 

static int add_privileges(cap_t caps) 
{ 
    cap_value_t value[3] = { CAP_SETPCAP, CAP_SETUID, CAP_SETGID }; 

    if (cap_set_flag(caps, CAP_PERMITTED, sizeof value/sizeof value[0], value, CAP_SET) == -1) 
     return errno; 

    if (cap_set_flag(caps, CAP_EFFECTIVE, sizeof value/sizeof value[0], value, CAP_SET) == -1) 
     return errno; 

    return 0; 
} 

int drop_privileges(const char *const user, const unsigned int capabilities) 
{ 
    uid_t uid; 
    gid_t gid; 
    cap_t caps; 

    /* Make sure user is neither NULL nor empty. */ 
    if (!user || !user[0]) 
     return errno = EINVAL; 

    /* Find the user. */ 
    { 
     struct passwd *pw; 

     pw = getpwnam(user); 
     if (!pw 
#ifdef UID_MIN 
      || pw->pw_uid < (uid_t)UID_MIN 
#endif 
#ifdef UID_MAX 
      || pw->pw_uid > (uid_t)UID_MAX 
#endif 
#ifdef GID_MIN 
      || pw->pw_gid < (gid_t)GID_MIN 
#endif 
#ifdef GID_MAX 
      || pw->pw_gid > (gid_t)GID_MAX 
#endif 
       ) 
      return errno = EINVAL; 

     uid = pw->pw_uid; 
     gid = pw->pw_gid; 

     endpwent(); 
    } 

    /* Install privileged capabilities. */ 
    caps = cap_init(); 
    if (!caps) 
     return errno = ENOMEM; 
    if (permit_effective(caps, capabilities)) { 
     const int cause = errno; 
     cap_free(caps); 
     return errno = cause; 
    } 
    if (add_privileges(caps)) { 
     const int cause = errno; 
     cap_free(caps); 
     return errno = cause; 
    } 
    if (cap_set_proc(caps) == -1) { 
     const int cause = errno; 
     cap_free(caps); 
     return errno = cause; 
    } 
    cap_free(caps); 

    /* Retain permitted capabilities over the identity change. */ 
    prctl(PR_SET_KEEPCAPS, 1UL, 0UL,0UL,0UL); 

    if (setresgid(gid, gid, gid) == -1) 
     return errno = EPERM; 

    if (initgroups(user, gid) == -1) 
     return errno = EPERM; 

    if (setresuid(uid, uid, uid) == -1) 
     return errno = EPERM; 

    /* Install unprivileged capabilities. */ 
    caps = cap_init(); 
    if (!caps) 
     return errno = ENOMEM; 
    if (permit_effective(caps, capabilities)) { 
     const int cause = errno; 
     cap_free(caps); 
     return errno = cause; 
    } 
    if (cap_set_proc(caps) == -1) { 
     const int cause = errno; 
     cap_free(caps); 
     return errno = cause; 
    } 
    cap_free(caps); 

    /* Reset standard KEEPCAPS behaviour. */ 
    prctl(PR_SET_KEEPCAPS, 0UL, 0UL,0UL,0UL); 

    /* Done. */ 
    return 0; 
} 
udp-broadcast.h

#ifndef UDP_BROADCAST_H 
#define UDP_BROADCAST_H 
#include <stdlib.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 

struct udp_socket { 
    struct sockaddr_in broadcast; /* Broadcast address */ 
    unsigned int  if_index; /* Interface index */ 
    int     descriptor; /* Socket descriptor */ 
}; 

extern int open_udp_broadcast(struct udp_socket *const udpsocket, 
           const char  *const interface, 
           int    const port); 

extern int udp_broadcast(const struct udp_socket *const udpsocket, 
         const void *const    data, 
         const size_t     size, 
         const int      flags); 

extern size_t udp_receive(const struct udp_socket *const udpsocket, 
          void *const     data, 
          const size_t     size_max, 
          const int      flags, 
          struct sockaddr_in  *const from_addr, 
          struct sockaddr_in  *const to_addr, 
          struct sockaddr_in  *const hdr_addr, 
          unsigned int   *const if_index); 

#endif /* UDP_BROADCAST_H */ 

PRIVILEGES_H の#define PRIVILEGES_H

#define NEED_CAP_NET_ADMIN   (1U << 0) 
#define NEED_CAP_NET_BIND_SERVICE (1U << 1) 
#define NEED_CAP_NET_RAW   (1U << 2) 

extern int drop_privileges(const char *const user, const unsigned int capabilities); 

#endif /* PRIVILEGES_H */ 

privileges.c #ifndefの:

#include <unistd.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <net/if.h> 
#include <errno.h> 
#include "udp-broadcast.h" 


int udp_broadcast(const struct udp_socket *const udpsocket, 
        const void *const    data, 
        const size_t     size, 
        const int      flags) 
{ 
    ssize_t n; 

    if (!udpsocket || udpsocket->broadcast.sin_family != AF_INET) 
     return errno = EINVAL; 

    if (!data || size < 1) 
     return 0; 

    n = sendto(udpsocket->descriptor, data, size, flags, 
       (const struct sockaddr *)&(udpsocket->broadcast), 
       sizeof (struct sockaddr_in)); 

    if (n == (ssize_t)-1) 
     return errno; 
    if (n == (ssize_t)size) 
     return 0; 
    return errno = EIO;  
} 


size_t udp_receive(const struct udp_socket *const udpsocket, 
        void *const     data, 
        const size_t     size_max, 
        const int      flags, 
        struct sockaddr_in  *const from_addr, 
        struct sockaddr_in  *const to_addr, 
        struct sockaddr_in  *const hdr_addr, 
        unsigned int   *const if_index) 
{ 
    char   ancillary[512]; 
    struct msghdr msg; 
    struct iovec iov[1]; 
    struct cmsghdr *cmsg; 
    ssize_t   n; 

    if (!data || size_max < 1 || !udpsocket) { 
     errno = EINVAL; 
     return (size_t)0; 
    } 

    /* Clear results, just in case. */ 
    if (from_addr) { 
     memset(from_addr, 0, sizeof *from_addr); 
     from_addr->sin_family = AF_UNSPEC; 
    } 
    if (to_addr) { 
     memset(to_addr, 0, sizeof *to_addr); 
     to_addr->sin_family = AF_UNSPEC; 
    } 
    if (hdr_addr) { 
     memset(hdr_addr, 0, sizeof *hdr_addr); 
     hdr_addr->sin_family = AF_UNSPEC; 
    } 
    if (if_index) 
     *if_index = 0U; 

    iov[0].iov_base = data; 
    iov[0].iov_len = size_max; 

    if (from_addr) { 
     msg.msg_name = from_addr; 
     msg.msg_namelen = sizeof (struct sockaddr_in); 
    } else { 
     msg.msg_name = NULL; 
     msg.msg_namelen = 0; 
    } 

    msg.msg_iov = iov; 
    msg.msg_iovlen = 1; 

    msg.msg_control = ancillary; 
    msg.msg_controllen = sizeof ancillary; 

    msg.msg_flags = 0; 

    n = recvmsg(udpsocket->descriptor, &msg, flags); 
    if (n == (ssize_t)-1) 
     return (size_t)0; /* errno set by recvmsg(). */ 
    if (n < (ssize_t)1) { 
     errno = EIO; 
     return (size_t)0; 
    } 

    /* Populate data from ancillary message, if requested. */ 
    if (to_addr || hdr_addr || if_index) 
     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) 
      if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { 
       const struct in_pktinfo *const info = CMSG_DATA(cmsg); 
       if (!info) 
        continue; 
       if (if_index) 
        *if_index = info->ipi_ifindex; 
       if (to_addr) { 
        to_addr->sin_family = AF_INET; 
        to_addr->sin_port = udpsocket->broadcast.sin_port; /* This is a guess. */ 
        to_addr->sin_addr = info->ipi_spec_dst; 
       } 
       if (hdr_addr) { 
        hdr_addr->sin_family = AF_INET; 
        hdr_addr->sin_port = udpsocket->broadcast.sin_port; /* A guess, again. */ 
        hdr_addr->sin_addr = info->ipi_addr; 
       } 
      } 

    errno = 0; 
    return (size_t)n; 
} 

int open_udp_broadcast(struct udp_socket *const udpsocket, 
         const char  *const interface, 
         int    const port) 
{ 
    const size_t interface_len = (interface) ? strlen(interface) : 0; 
    const int set_flag = 1; 
    int   sockfd; 

    if (udpsocket) { 
     memset(udpsocket, 0, sizeof *udpsocket); 
     udpsocket->broadcast.sin_family = AF_INET; 
     udpsocket->broadcast.sin_addr.s_addr = INADDR_BROADCAST; 
     if (port >= 1 && port <= 65535) 
      udpsocket->broadcast.sin_port = htons(port); 
     udpsocket->descriptor = -1; 
    } 

    if (!udpsocket || interface_len < 1 || port < 1 || port > 65535) 
     return errno = EINVAL; 

    /* Generic UDP socket. */ 
    sockfd = socket(AF_INET, SOCK_DGRAM, 0); 
    if (sockfd == -1) 
     return errno; 

    /* Set SO_REUSEADDR if possible. */ 
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &set_flag, sizeof set_flag); 

    /* Set IP_FREEBIND if possible. */ 
    setsockopt(sockfd, IPPROTO_IP, IP_FREEBIND, &set_flag, sizeof set_flag); 

    /* We need broadcast capability. */ 
    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &set_flag, sizeof set_flag) == -1) { 
     const int real_errno = errno; 
     close(sockfd); 
     return errno = real_errno; 
    } 

    /* We want the IP_PKTINFO ancillary messages, to determine target address 
    * and interface index. */ 
    if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &set_flag, sizeof set_flag) == -1) { 
     const int real_errno = errno; 
     close(sockfd); 
     return errno = real_errno; 
    } 

    /* We bind to the broadcast address. */ 
    if (bind(sockfd, (const struct sockaddr *)&(udpsocket->broadcast), sizeof udpsocket->broadcast) == -1) { 
     const int real_errno = errno; 
     close(sockfd); 
     return errno = real_errno; 
    } 

    /* Finally, we bind to the specified interface. */ 
    if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, interface, interface_len) == -1) { 
     const int real_errno = errno; 
     close(sockfd); 
     return errno = real_errno; 
    } 

    udpsocket->descriptor = sockfd; 

    udpsocket->if_index = if_nametoindex(interface); 

    errno = 0; 
    return 0; 
} 

main.c

gcc -Wall -Wextra -O2 -c privileges.c 
gcc -Wall -Wextra -O2 -c udp-broadcast.c 
gcc -Wall -Wextra -O2 -c main.c 
gcc -Wall -Wextra main.o udp-broadcast.o privileges.o -lcap -o example 

を用い

#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <signal.h> 
#include <stdio.h> 
#include <netdb.h> 
#include <errno.h> 
#include "privileges.h" 
#include "udp-broadcast.h" 

static volatile sig_atomic_t done_triggered = 0; 
static volatile sig_atomic_t reload_triggered = 0; 

static void done_handler(int signum) 
{ 
    __sync_bool_compare_and_swap(&done_triggered, (sig_atomic_t)0, (sig_atomic_t)signum); 
} 

static void reload_handler(int signum) 
{ 
    __sync_bool_compare_and_swap(&reload_triggered, (sig_atomic_t)0, (sig_atomic_t)signum); 
} 

static int install_handler(const int signum, void (*handler)(int)) 
{ 
    struct sigaction act; 
    memset(&act, 0, sizeof act); 
    sigemptyset(&act.sa_mask); 
    act.sa_handler = handler; 
    act.sa_flags = 0; 
    if (sigaction(signum, &act, NULL) == -1) 
     return errno; 
    return 0; 
} 

/* Return 0 if done_triggered or reload_triggered, nonzero otherwise. 
* Always clears reload_triggered. 
*/ 
static inline int keep_running(void) 
{ 
    if (done_triggered) 
     return 0; 
    return !__sync_fetch_and_and(&reload_triggered, (sig_atomic_t)0); 
} 

static const char *ipv4_address(const void *const addr) 
{ 
    static char buffer[16]; 
    char   *end = buffer + sizeof buffer; 
    unsigned char byte[4]; 

    if (!addr) 
     return "(none)"; 

    memcpy(byte, addr, 4); 

    *(--end) = '\0'; 
    do { 
     *(--end) = '0' + (byte[3] % 10); 
     byte[3] /= 10U; 
    } while (byte[3]); 
    *(--end) = '.'; 
    do { 
     *(--end) = '0' + (byte[2] % 10); 
     byte[2] /= 10U; 
    } while (byte[2]); 
    *(--end) = '.'; 
    do { 
     *(--end) = '0' + (byte[1] % 10); 
     byte[1] /= 10U; 
    } while (byte[1]); 
    *(--end) = '.'; 
    do { 
     *(--end) = '0' + (byte[0] % 10); 
     byte[0] /= 10U; 
    } while (byte[0]); 

    return (const char *)end; 
} 

int main(int argc, char *argv[]) 
{ 
    int port; 
    char dummy; 

    /* Check usage. */ 
    if (argc != 4 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { 
     fprintf(stderr, "\n"); 
     fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]); 
     fprintf(stderr, "  %s USERNAME INTERFACE PORT\n", argv[0]); 
     fprintf(stderr, "Where:\n"); 
     fprintf(stderr, "  USERNAME is the unprivileged user to run as,\n"); 
     fprintf(stderr, "  INTERFACE is the interface to bind to, and\n"); 
     fprintf(stderr, "  PORT  is the UDP/IPv4 port number to use.\n"); 
     fprintf(stderr, "\n"); 
     return EXIT_FAILURE; 
    } 

    /* Parse the port into a number. */ 
    if (sscanf(argv[3], "%d %c", &port, &dummy) != 1 || port < 1 || port > 65535) { 
     struct servent *serv = getservbyname(argv[3], "udp"); 
     if (serv && serv->s_port > 1 && serv->s_port < 65536) { 
      port = serv->s_port; 
      endservent(); 
     } else { 
      endservent(); 
      fprintf(stderr, "%s: Invalid port.\n", argv[3]); 
      return EXIT_FAILURE; 
     } 
    } 

    /* Drop privileges. */ 
    if (drop_privileges(argv[1], NEED_CAP_NET_RAW)) { 
     fprintf(stderr, "%s.\n", strerror(errno)); 
     return EXIT_FAILURE; 
    } 

    /* Install signal handlers. */ 
    if (install_handler(SIGINT, done_handler) || 
     install_handler(SIGTERM, done_handler) || 
     install_handler(SIGHUP, reload_handler) || 
     install_handler(SIGUSR1, reload_handler)) { 
     fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno)); 
     return EXIT_FAILURE; 
    } 

    fprintf(stderr, "Send a SIGINT (Ctrl+C) or SIGTERM to stop the service:\n"); 
    fprintf(stderr, "\tkill -SIGTERM %ld\n", (long)getpid()); 
    fprintf(stderr, "Send a SIGHUP or SIGUSR1 to have the service reload and rebroadcast:\n"); 
    fprintf(stderr, "\tkill -SIGHUP %ld\n", (long)getpid()); 
    fprintf(stderr, "Privileges dropped successfully.\n\n"); 
    fflush(stderr); 

    while (!done_triggered) { 
     struct udp_socket s; 

     if (open_udp_broadcast(&s, argv[2], port)) { 
      fprintf(stderr, "%s port %s: %s.\n", argv[2], argv[3], strerror(errno)); 
      return EXIT_FAILURE; 
     } 

     if (udp_broadcast(&s, "Hello?", 6, MSG_NOSIGNAL)) { 
      fprintf(stderr, "%s port %s: Broadcast failed: %s.\n", argv[2], argv[3], strerror(errno)); 
      close(s.descriptor); 
      return EXIT_FAILURE; 
     } 

     if (s.if_index) 
      fprintf(stderr, "Broadcast sent using interface %s (index %u); waiting for responses.\n", argv[2], s.if_index); 
     else 
      fprintf(stderr, "Broadcast sent using interface %s; waiting for responses.\n", argv[2]); 
     fflush(stderr); 

     while (keep_running()) { 
      struct sockaddr_in from_addr, to_addr, hdr_addr; 
      unsigned char  data[512]; 
      unsigned int  if_index; 
      size_t    size, i; 

      size = udp_receive(&s, data, sizeof data, 0, &from_addr, &to_addr, &hdr_addr, &if_index); 
      if (size > 0) { 
       printf("Received %zu bytes:", size); 
       for (i = 0; i < size; i++) 
        if (i & 15) 
         printf(" %02x", data[i]); 
        else 
         printf("\n\t%02x", data[i]); 
       if (if_index) 
        printf("\n\t Index: %u", if_index); 
       printf("\n\t From: %s", ipv4_address(&from_addr.sin_addr)); 
       printf("\n\t To: %s", ipv4_address(&to_addr.sin_addr)); 
       printf("\n\tHeader: %s", ipv4_address(&hdr_addr.sin_addr)); 
       printf("\n"); 
       fflush(stdout); 
      } else 
      if (errno != EINTR) { 
       fprintf(stderr, "%s\n", strerror(errno)); 
       break; 
      } 
     } 

     close(s.descriptor); 
    } 

    fprintf(stderr, "Exiting.\n"); 
    return EXIT_SUCCESS; 
} 

コンパイルとに結合するためのインタフェースとして実行する権限のないユーザ名を指定して、ルートとしてexampleを実行し、そしてパラメータとしてのUDPポート番号:

sudo ./example yourdaemonuser eth0 4000 

今は1台のラップトップしか使用していないため、受信側は基本的にはテストされていません。私はCAP_NET_RAWが十分であることを知っています(x86-64ではLinuxカーネル4.2.0-27)、UDPブロードキャストの送信はイーサネットインターフェイスのアドレスから255.255.255.255:portへの発信として表示されますが、送信する別のマシンはありませんデーモンへの応答の例(NetCat:printf 'Response!' | nc -u4 -q2y interface-address portなどを使用すると簡単になります)。

上記のコード品質は初期テストグレードです。私は何もこれを必要とせず、自分のお尻から話をしていないことを確認したかっただけなので、私はコードをきれいにすることや信頼できるように努力していません。

お困りですか?コメント?

+0

これは大きな疑問に答えるものです。私の最初の問題は、 'INADDR_BROADCAST'を聞き、放送が受信されたインターフェースを知り、同じインターフェースを使って' INADDR_BROADCAST'に送る必要があることです。私のテストでは、 'CAP_NET_RAW'は' SO_BINDTODEVICE'では機能しませんでした。本当の 'root'だけが実行しました。その場合、私はこのsockoptを設定してから権限を落とすことしかできないだろうか? – TabascoEye

+0

@TabascoEye:私は調査し(いくつかのコード例を書いてそれを自分でテストする)、これについてあなたに連絡します。 –

+0

Hmm。私はカーネルソースhttp://lxr.free-electrons.com/source/net/core/sock.c#L569でこれを見つけましたので、うまくいくはずです。しかし、それは私の簡単な小さなテストではありません。私はちょうどstackoverflowの別の質問にそれを入れます – TabascoEye

関連する問題