[3296] in linux-net channel archive
bug in tcp.c. How to fix?
daemon@ATHENA.MIT.EDU (A.N.Kuznetsov)
Tue Jun 18 14:37:46 1996
From: "A.N.Kuznetsov" <kuznet@ms2.inr.ac.ru>
To: alan@cymru.net (Alan Cox)
Date: Tue, 18 Jun 1996 17:30:25 +0400 (MSD)
Cc: linux-net@vger.rutgers.edu
In-Reply-To: <199606171434.PAA17126@snowcrash.cymru.net> from "Alan Cox" at Jun 17, 96 03:34:44 pm
Hello!
recv urgent data does not advance "copied" pointer,
so that when 2 or more urgent data chunks follow in row,
all they except for the last are duplicated(!) as usual data.
Test program follows.
Expected:
OOB1 A
OOB2 B
OOB3 C
Got:
OOB1 A
OOB2 B
OOB3 C
INLINE: [AB]
Please, NOTE that this bug has nothing to do with the well-known
BSD interface bug: "when two chunks of urgent data arrive
before user read the first one it goes to ordinary data stream"
I see no good fix for this problem now. Apparently, we must
advance copied pointer and cleanup_rbuf somewhere after tcp_recv_urg.
Bug is pretty serious, it affects rlogin sometimes.
(And fatally, if rlogin is encrypted).
Alexey Kuznetsov.
Test program.
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <errno.h>
main()
{
int sender, receiver;
struct sockaddr_in addr;
int res;
int addrsize = sizeof(addr);
receiver = socket(AF_INET, SOCK_STREAM, 0);
if (receiver < 0) {
perror("socket");
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(12345);
res = bind(receiver, &addr, sizeof(addr));
if (res < 0) {
perror("bind");
exit(1);
}
if (fork()) {
int fd;
unsigned char c;
char buf[3];
for (;;) {
if (listen(receiver, 1) < 0)
continue;
fd = accept(receiver, &addr, &addrsize);
if (fd < 0) {
perror("accept");
exit(1);
}
close(receiver);
break;
}
do {
res = recv(fd, &c, 1, MSG_OOB);
} while (res != 1);
printf("OOB1 %c\n", c);
do {
res = recv(fd, &c, 1, MSG_OOB);
} while (res != 1);
printf("OOB2 %c\n", c);
do {
res = recv(fd, &c, 1, MSG_OOB);
} while (res != 1);
printf("OOB3 %c\n", c);
res = read(fd, buf, 3);
if (res > 0) {
printf("INLINE: [%.*s]\n", res, buf);
}
exit(0);
}
close(receiver);
sleep(5);
sender = socket(AF_INET, SOCK_STREAM, 0);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(0x7F000001);
addr.sin_port = htons(12345);
connect(sender, &addr, addrsize);
send(sender, "A", 1, MSG_OOB);
sleep(5);
send(sender, "B", 1, MSG_OOB);
sleep(5);
send(sender, "C", 1, MSG_OOB);
sleep(5);
exit(0);
}