* SO_REUSEADDR with UDP (again) @ 2010-04-13 9:34 Michal Svoboda 2010-04-13 10:39 ` Eric Dumazet 0 siblings, 1 reply; 6+ messages in thread From: Michal Svoboda @ 2010-04-13 9:34 UTC (permalink / raw) To: netdev [-- Attachment #1: Type: text/plain, Size: 1447 bytes --] Hello, (redirected here from LKML) I found SO_REUSEADDR on UDP sockets to behave somewhat nasty. If you create a UDP socket with that flag and bind it to a port, then anyone doing the same later will "steal" your packets, ie. 1. process A binds to port 12345 with SO_REUSEADDR, packets to that port go to process A 2. process B binds to port 12345 with SO_REUSEADDR, packets to that port now go to process B 3. A dies, fires up again, packets go back to A 4. A dies, does not fire up, packets go to B, as if they were stacked And this works even if A and B are owned by different users, thus anyone can "steal" packets from anyone as long as they use SO_REUSEADDR. However, in most programs that's the default. Furthermore, one can lock-out a particular source from being "stolen" by using connect() to that source, ie. 1. process A binds to port 12345 with SO_REUSEADDR, gets the packets 2. B does the same, gets the packets, but also connect()s to the source of the packets 3. A can now restart or try to bind again, but does not get the packets (from that source) (I haven't tested the case if A also issues a connect() even if it does not receive packets.) All of this seems confusing to me, and the fact that users can steal packets from each other seems like a mild security risk. I've found some discussions about this from circa 2002, but the above cases were not mentioned. So - a problem or not? Michal Svoboda [-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --] ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: SO_REUSEADDR with UDP (again) 2010-04-13 9:34 SO_REUSEADDR with UDP (again) Michal Svoboda @ 2010-04-13 10:39 ` Eric Dumazet 2010-04-13 11:27 ` Michal Svoboda 0 siblings, 1 reply; 6+ messages in thread From: Eric Dumazet @ 2010-04-13 10:39 UTC (permalink / raw) To: Michal Svoboda; +Cc: netdev Le mardi 13 avril 2010 à 11:34 +0200, Michal Svoboda a écrit : > Hello, > > (redirected here from LKML) > > I found SO_REUSEADDR on UDP sockets to behave somewhat nasty. If you > create a UDP socket with that flag and bind it to a port, then anyone > doing the same later will "steal" your packets, ie. > > 1. process A binds to port 12345 with SO_REUSEADDR, packets to that port > go to process A why process A sets SO_REUSEADDR ? > 2. process B binds to port 12345 with SO_REUSEADDR, packets to that port > now go to process B Or not... this is implementation (un)defined. > 3. A dies, fires up again, packets go back to A Or not. Not documented. > 4. A dies, does not fire up, packets go to B, as if they were stacked > > And this works even if A and B are owned by different users, thus anyone > can "steal" packets from anyone as long as they use SO_REUSEADDR. > However, in most programs that's the default. Really ? They are very buggy then. > > Furthermore, one can lock-out a particular source from being "stolen" by > using connect() to that source, ie. > > 1. process A binds to port 12345 with SO_REUSEADDR, gets the packets > 2. B does the same, gets the packets, but also connect()s to the source > of the packets > 3. A can now restart or try to bind again, but does not get the packets > (from that source) > > (I haven't tested the case if A also issues a connect() even if it does > not receive packets.) > > All of this seems confusing to me, and the fact that users can steal > packets from each other seems like a mild security risk. I've found some > discussions about this from circa 2002, but the above cases were not > mentioned. So - a problem or not? > > Why do you use REUSEADDR ? This is doing what is documented. SO_REUSEADDR Indicates that the rules used in validating addresses supplied in a bind(2) call should allow reuse of local addresses. For AF_INET sockets this means that a socket may bind, except when there is an active listening socket bound to the address. When the listening socket is bound to INADDR_ANY with a specific port then it is not possible to bind to this port for any local address. Argument is an integer boolean flag. An UDP application wanting a port for its exclusive use dont set REUSEADDR, or basically allows anybody to bind an udp socket to same port, and potentially steal incoming frames. REUSEADDR is usually used when an application has several sockets bound to same port, but different IP addresses (or bound to different devices) ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: SO_REUSEADDR with UDP (again) 2010-04-13 10:39 ` Eric Dumazet @ 2010-04-13 11:27 ` Michal Svoboda 2010-04-13 12:21 ` Eric Dumazet 0 siblings, 1 reply; 6+ messages in thread From: Michal Svoboda @ 2010-04-13 11:27 UTC (permalink / raw) To: netdev [-- Attachment #1: Type: text/plain, Size: 1359 bytes --] Eric Dumazet wrote: > Why do you use REUSEADDR ? This is doing what is documented. > > SO_REUSEADDR > Indicates that the rules used in validating addresses supplied > in a bind(2) call should allow reuse of local addresses. For > AF_INET sockets this means that a socket may bind, except when > there is an active listening socket bound to the address. When > the listening socket is bound to INADDR_ANY with a specific > port then it is not possible to bind to this port for any local > address. Argument is an integer boolean flag. I read it 10 times but it doesn't say anything about stealing frames, or implementation-defined behavior in this case. > An UDP application wanting a port for its exclusive use dont set > REUSEADDR, or basically allows anybody to bind an udp socket to same > port, and potentially steal incoming frames. That's fair enough, I will talk to the developers of the "very buggy" applications that use this flag and ask them to reconsider. > REUSEADDR is usually used when an application has several sockets bound > to same port, but different IP addresses (or bound to different devices) I just tried that and you can bind to different IPs without REUSEADDR. Michal Svoboda [-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --] ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: SO_REUSEADDR with UDP (again) 2010-04-13 11:27 ` Michal Svoboda @ 2010-04-13 12:21 ` Eric Dumazet 2010-04-13 16:23 ` Michal Svoboda 0 siblings, 1 reply; 6+ messages in thread From: Eric Dumazet @ 2010-04-13 12:21 UTC (permalink / raw) To: Michal Svoboda; +Cc: netdev Le mardi 13 avril 2010 à 13:27 +0200, Michal Svoboda a écrit : > Eric Dumazet wrote: > > Why do you use REUSEADDR ? This is doing what is documented. > > > > SO_REUSEADDR > > Indicates that the rules used in validating addresses supplied > > in a bind(2) call should allow reuse of local addresses. For > > AF_INET sockets this means that a socket may bind, except when > > there is an active listening socket bound to the address. When > > the listening socket is bound to INADDR_ANY with a specific > > port then it is not possible to bind to this port for any local > > address. Argument is an integer boolean flag. > > I read it 10 times but it doesn't say anything about stealing frames, or > implementation-defined behavior in this case. If it is not documented, it is implementation defined. > > > An UDP application wanting a port for its exclusive use dont set > > REUSEADDR, or basically allows anybody to bind an udp socket to same > > port, and potentially steal incoming frames. > > That's fair enough, I will talk to the developers of the "very buggy" > applications that use this flag and ask them to reconsider. ;) > > > REUSEADDR is usually used when an application has several sockets bound > > to same port, but different IP addresses (or bound to different devices) > > I just tried that and you can bind to different IPs without REUSEADDR. Of course it is possible ! REUSEADDR allows following : (Note that both sockets MUST have requested REUSEADDR=1) #include <sys/socket.h> #include <netinet/in.h> #include <string.h> main() { int sock1, sock2; struct sockaddr_in addr; int on = 1; memset(&addr, 0, sizeof(addr)); addr.sin_port = htons(3444); addr.sin_family = AF_INET; sock1 = socket(AF_INET, SOCK_DGRAM, 0); setsockopt(sock1, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); addr.sin_addr.s_addr = htonl(0x7f000001); if (bind(sock1, (struct sockaddr *)&addr, sizeof(addr))) perror("bind1"); sock2 = socket(AF_INET, SOCK_DGRAM, 0); setsockopt(sock2, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); addr.sin_addr.s_addr = INADDR_ANY; /* or htonl(0x7f000001); */ if (bind(sock2, (struct sockaddr *)&addr, sizeof(addr))) perror("bind2"); } If an application didnt specified REUSEADDR=1, then its UDP port is private, it cannot be stolen. Therefore, applications should not use REUSEADDR on unicast UDP, unless it is a non security issue (for example, if it is able to react to any new IP addresses added by the administrator on the machine, and complain loudly if another application could bind() before itself) REUSADDR has a meaning for multicast, but for unicast... this is hardly useful ? About the connect() thing, its also a fact that connected sockets have a higher priority (they'll receive incoming frames, their score his higher than a non connected socket, if source of the packet matches the connect destination of course). Same thing if you play with BINDTODEVICE. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: SO_REUSEADDR with UDP (again) 2010-04-13 12:21 ` Eric Dumazet @ 2010-04-13 16:23 ` Michal Svoboda 2010-04-13 16:36 ` Eric Dumazet 0 siblings, 1 reply; 6+ messages in thread From: Michal Svoboda @ 2010-04-13 16:23 UTC (permalink / raw) To: netdev [-- Attachment #1: Type: text/plain, Size: 1469 bytes --] Eric Dumazet wrote: > sock1 = socket(AF_INET, SOCK_DGRAM, 0); > setsockopt(sock1, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); > addr.sin_addr.s_addr = htonl(0x7f000001); > if (bind(sock1, (struct sockaddr *)&addr, sizeof(addr))) > perror("bind1"); > > sock2 = socket(AF_INET, SOCK_DGRAM, 0); > setsockopt(sock2, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); > addr.sin_addr.s_addr = INADDR_ANY; /* or htonl(0x7f000001); */ > if (bind(sock2, (struct sockaddr *)&addr, sizeof(addr))) > perror("bind2"); > } Well, now if I send to 127.0.0.1, who gets the datagram? I guess sock2, so it steals from sock1. What practical use does this have? > Therefore, applications should not use REUSEADDR on unicast UDP, unless > it is a non security issue (for example, if it is able to react to any > new IP addresses added by the administrator on the machine, and complain > loudly if another application could bind() before itself) I don't think that in that case REUSEADDR would be useful because you can already claim new addresses without it, either by binding a separate socket to each IP or by binding to 0.0.0.0. Moreover the detection of the "complain" case would be very tricky, at least on first sight. > REUSADDR has a meaning for multicast, but for unicast... this is hardly > useful ? So would it be somehow possible to deliver the datagram to both sockets (for example if they would be SO_BROADCAST as well)? Michal Svoboda [-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --] ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: SO_REUSEADDR with UDP (again) 2010-04-13 16:23 ` Michal Svoboda @ 2010-04-13 16:36 ` Eric Dumazet 0 siblings, 0 replies; 6+ messages in thread From: Eric Dumazet @ 2010-04-13 16:36 UTC (permalink / raw) To: Michal Svoboda; +Cc: netdev Le mardi 13 avril 2010 à 18:23 +0200, Michal Svoboda a écrit : > Eric Dumazet wrote: > > sock1 = socket(AF_INET, SOCK_DGRAM, 0); > > setsockopt(sock1, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); > > addr.sin_addr.s_addr = htonl(0x7f000001); > > if (bind(sock1, (struct sockaddr *)&addr, sizeof(addr))) > > perror("bind1"); > > > > sock2 = socket(AF_INET, SOCK_DGRAM, 0); > > setsockopt(sock2, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); > > addr.sin_addr.s_addr = INADDR_ANY; /* or htonl(0x7f000001); */ > > if (bind(sock2, (struct sockaddr *)&addr, sizeof(addr))) > > perror("bind2"); > > } > > Well, now if I send to 127.0.0.1, who gets the datagram? I guess sock2, > so it steals from sock1. What practical use does this have? > No, sock1 will get the frame. In udp receive (kernel), we chose the socket with highest score. A socket bound to an IP address (not 0.0.0.0) has a bonus. A connected socket has an extra bonus. A socket bound to a device has an extra bonus. > > Therefore, applications should not use REUSEADDR on unicast UDP, unless > > it is a non security issue (for example, if it is able to react to any > > new IP addresses added by the administrator on the machine, and complain > > loudly if another application could bind() before itself) > > I don't think that in that case REUSEADDR would be useful because you > can already claim new addresses without it, either by binding a separate > socket to each IP or by binding to 0.0.0.0. Moreover the detection of > the "complain" case would be very tricky, at least on first sight. > > > REUSADDR has a meaning for multicast, but for unicast... this is hardly > > useful ? > > So would it be somehow possible to deliver the datagram to both sockets > (for example if they would be SO_BROADCAST as well)? Not without a change in kernel. AFAIK no other OS do that anyway. ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2010-04-13 16:36 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-04-13 9:34 SO_REUSEADDR with UDP (again) Michal Svoboda 2010-04-13 10:39 ` Eric Dumazet 2010-04-13 11:27 ` Michal Svoboda 2010-04-13 12:21 ` Eric Dumazet 2010-04-13 16:23 ` Michal Svoboda 2010-04-13 16:36 ` Eric Dumazet
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox