Note that there are some explanatory texts on larger screens.

plurals
  1. POProblems with SO_BINDTODEVICE Linux socket option
    primarykey
    data
    text
    <p>I have a PC with two network cards. One (<code>eth0</code>) is for LAN/internet and the other for UDP communication with one microcontroller device. The microcontroller has an IP (192.168.7.2) and a MAC address. The second pc network adapter (<code>eth1</code>) has 192.168.7.1.</p> <p>The microcontroller has a very simple IP stack, so the easiest way for the mc to send UDP packets is to broadcast them.</p> <p>On the PC side I'd like to receive the broadcasts - but only from <code>eth1</code>. So I try to bind the UDP socket to the <code>eth1</code> device. </p> <p>The problems (source code below):</p> <ol> <li><p><code>setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, device, sizeof(device))</code> requires root privileges, why? (setting other options works as user)</p></li> <li><p><code>getsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)buffer, &amp;opt_length)</code> gives "Protocol not available". I would like to read back the device I set via <code>setsockopt</code> command.</p></li> <li><p>Where can I find good info? I checked some Linux-programming, network books, but for example the <code>SO_BINDTODEVICE</code> option I've only found on the internet.</p></li> </ol> <p>My lengthy (dirty) test program shows the problems. Setting and getting back the <code>SO_RCVTIMEO</code> and <code>SO_BROADCAST</code> options works as expected.</p> <p>Running the code as user exits with:</p> <pre class="lang-none prettyprint-override"><code>could not set SO_BINDTODEVICE (Operation not permitted)" </code></pre> <p>Running with sudo gives:</p> <pre class="lang-none prettyprint-override"><code>SO_BINDTODEVICE set ./mc-test: could not get SO_BINDTODEVICE (Protocol not available) </code></pre> <p>So, setting the option seems to work but reading it back is not possible?</p> <pre><code>/* SO_BINDTODEVICE test */ #include &lt;sys/types.h&gt; #include &lt;sys/socket.h&gt; #include &lt;netinet/in.h&gt; #include &lt;arpa/inet.h&gt; #include &lt;netdb.h&gt; #include &lt;stdio.h&gt; #include &lt;unistd.h&gt; #include &lt;string.h&gt; #include &lt;stdlib.h&gt; #include &lt;sys/time.h&gt; #include &lt;errno.h&gt; #define MC_IP "192.168.7.2" #define MC_PORT (54321) #define MY_PORT (54321) #define MY_DEVICE "eth1" #define BUFFERSIZE (1000) /* global variables */ int sock; struct sockaddr_in MC_addr; struct sockaddr_in my_addr; char buffer[BUFFERSIZE]; int main(int argc, char *argv[]) { unsigned int echolen, clientlen; int rc, n; char opt_buffer[1000]; struct protoent *udp_protoent; struct timeval receive_timeout; int optval; socklen_t opt_length; /* Create the UDP socket */ if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) &lt; 0) { printf ("%s: failed to create UDP socket (%s) \n", argv[0], strerror(errno)); exit (EXIT_FAILURE); } printf ("UDP socket created\n"); /* set the recvfrom timeout value */ receive_timeout.tv_sec = 5; receive_timeout.tv_usec = 0; rc=setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &amp;receive_timeout, sizeof(receive_timeout)); if (rc != 0) { printf ("%s: could not set SO_RCVTIMEO (%s)\n", argv[0], strerror(errno)); exit (EXIT_FAILURE); } printf ("set timeout to\ntime [s]: %d\ntime [ms]: %d\n", receive_timeout.tv_sec, receive_timeout.tv_usec); /* verify the recvfrom timeout value */ rc=getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &amp;receive_timeout, &amp;opt_length); if (rc != 0) { printf ("%s: could not get socket options (%s)\n", argv[0], strerror(errno)); exit (EXIT_FAILURE); } printf ("timeout value\ntime [s]: %d\ntime [ms]: %d\n", receive_timeout.tv_sec, receive_timeout.tv_usec); /* allow broadcast messages for the socket */ int true = 1; rc=setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &amp;true, sizeof(true)); if (rc != 0) { printf ("%s: could not set SO_BROADCAST (%s)\n", argv[0], strerror(errno)); exit (EXIT_FAILURE); } printf ("set SO_BROADCAST\n"); /* verify SO_BROADCAST setting */ rc=getsockopt(sock, SOL_SOCKET, SO_BROADCAST, &amp;optval, &amp;opt_length); if (optval != 0) { printf("SO_BROADCAST is enabled\n"); } /* bind the socket to one network device */ const char device[] = MY_DEVICE; rc=setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, device, sizeof(device)); if (rc != 0) { printf ("%s: could not set SO_BINDTODEVICE (%s)\n", argv[0], strerror(errno)); exit (EXIT_FAILURE); } printf ("SO_BINDTODEVICE set\n"); /* verify SO_BINDTODEVICE setting */ rc = getsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)buffer, &amp;opt_length); if (rc != 0) { printf ("%s: could not get SO_BINDTODEVICE (%s)\n", argv[0], strerror(errno)); exit (EXIT_FAILURE); } if (rc == 0) { printf("SO_BINDTODEVICE is: %s\n", buffer); } /* Construct the server sockaddr_in structure */ memset(&amp;MC_addr, 0, sizeof(MC_addr)); /* Clear struct */ MC_addr.sin_family = AF_INET; /* Internet/IP */ MC_addr.sin_addr.s_addr = inet_addr(MC_IP); /* IP address */ MC_addr.sin_port = htons(MC_PORT); /* server port */ /* bind my own Port */ my_addr.sin_family = AF_INET; my_addr.sin_addr.s_addr = INADDR_ANY; /* INADDR_ANY all local addresses */ my_addr.sin_port = htons(MY_PORT); rc = bind (sock, (struct sockaddr *) &amp;my_addr, sizeof(my_addr)); if (rc &lt; 0) { printf ("%s: could not bind port (%s)\n", argv[0], strerror(errno)); exit (EXIT_FAILURE); } printf ("port bound\n"); /* identify mc */ buffer[0] = (char)1; buffer[1] = (char)0; send_data (buffer, 2); printf ("sent command: %d\n", (char)buffer[0]); rc=receive_data(buffer); printf ("%d bytes received\n", rc); buffer[rc] = (char)0; /* string end symbol */ printf ("%d - %s\n", (int)(char)buffer[0], &amp;buffer[1]); close(sock); printf ("socket closed\n"); exit(0); } /* send data to the MC *****************************************************/ /* buffer points to the bytes to send */ /* buf_length is the number of bytes to send */ /* returns allways 0 */ int send_data( char *buffer, int buf_length ) { int rc; rc = sendto (sock, buffer, buf_length, 0, (struct sockaddr *) &amp;MC_addr, sizeof(MC_addr)); if (rc &lt; 0) { printf ("could not send data\n"); close (sock); exit (EXIT_FAILURE); } return(0); } /* receive data from the MC *****************************************************/ /* buffer points to the memory for the received data */ /* max BUFFERSIZE bytes can be received */ /* returns number of bytes received */ int receive_data(char *buffer) { int rc, MC_addr_length; MC_addr_length = sizeof(MC_addr); rc = recvfrom (sock, buffer, BUFFERSIZE, 0, (struct sockaddr *) &amp;MC_addr, &amp;MC_addr_length); if (rc &lt; 0) { printf ("could not receive data\n"); close (sock); exit (EXIT_FAILURE); } return(rc); } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload