Hi, It seems sendto() can return EACCES for UDP as well; the current man page in git only says it can return EACCES for Unix sockets: EACCES (For UNIX domain sockets, which are identified by pathname) Write permission is denied on the destination socket file, or search permission is denied for one of the directories the path prefix. (See path_resolution(7).) I was able to make sendto() return EACCES if I try to send from 192.168.1.1/24 to 192.168.1.0. I think the relevant code (in kernel 2.6.38, but also present in 2.6.7 and 2.6.32, the 2 kernels we use) is this (net/ipv4/udp.c, udp_sendmsg()): 910 err = -EACCES; 911 if ((rt->rt_flags & RTCF_BROADCAST) && 912 !sock_flag(sk, SOCK_BROADCAST)) 913 goto out; So I guess if the kernel finds a route to the destination and it's a broadcast route (and the socket doesn't have the broadcast flag), then it returns EACCES. I can verify the behavior with a very simple program (attached). I've run it on my Ubuntu 10.10 (2.6.35 kernel) and got this: stefan@spuiu-vml2:~/src/test/broadcast$ ./broadcast_test 10.205.20.94 10.205.20.1 sendto() returned 4 stefan@spuiu-vml2:~/src/test/broadcast$ ./broadcast_test 10.205.20.94 10.205.20.0 sendto() returned negative, errno: 13/Permission denied (10.205.20.94 is my local IP, of course). How about updating the send.2 page like this? diff --git a/man2/send.2 b/man2/send.2 index 69287fb..4d2faed 100644 --- a/man2/send.2 +++ b/man2/send.2 @@ -288,6 +288,8 @@ or search permission is denied for one of the directories the path prefix. (See .BR path_resolution (7).) +(For UDP sockets) An attempt was made to sendto() to a +network/broadcast address like it was a unicast address. .TP .BR EAGAIN " or " EWOULDBLOCK .\" Actually EAGAIN on Linux Thanks, Stefan.
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> #include <stdlib.h> int main(int argc, char **argv) { int sock; if (argc < 2) { printf("Usage: %s local_address destination_address\n", argv[0]); exit(1); } sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { perror("socket"); return -1; } struct sockaddr_in local_addr; local_addr.sin_family = AF_INET; local_addr.sin_port = htons(1234); local_addr.sin_addr.s_addr = inet_addr(argv[1]); int ret = bind(sock, (struct sockaddr *) &local_addr, sizeof(local_addr)); if (ret < 0) { perror("bind"); return -1; } struct sockaddr_in remote_addr; remote_addr.sin_family = AF_INET; remote_addr.sin_port = htons(1234); remote_addr.sin_addr.s_addr = inet_addr(argv[2]); ret = sendto(sock, "blah", 4, 0, (struct sockaddr *)&remote_addr, sizeof(remote_addr)); if (ret < 0) { printf("sendto() returned negative, errno: %d/%m\n", errno); } else { printf("sendto() returned %d\n", ret); } return 0; }