On 2004-03-27 22:33:49 +0000, Tim Meadowcroft wrote: > In particular, a client can open two different sockets to the listening socket > on a single host (eg web browser opens 2 connections to port 80 on the same > host), and so the 4-tuple shows 2 connections differentiated only by the > client socket number, but the _client_ socket numbers are always unique even > when speaking to different hosts.
Yes, but that's only because the OS chooses unused port numbers (not
socket numbers) if left to its own devices. The application can easily
reuse the same port for all outgoing connections, if these connections
go to different hosts or ports.
> The stack for the server socket (the one
> that called listen()) de-multiplexes input packets based on the client
> IP+port and hands it off to the appropriate file descriptor returned by
> accept(), but there is no de-multiplexing on the client side - and I'm pretty
> sure it would break a huge amount of existing code if anyone wrote a TCP
> stack that did so (which I suppose it could do, given that the client socket
> number isn't actually assigned until the connect() call returns).
It can't break anything, because the FTP protocol requires the server to
originate all data connections from port 20 (unless explicitely told
otherwise by the client). So such breakage would be detected the first
time somebody tried to implement an FTP server on that OS.
Here is a simple test program to demonstrate the technique:
---8<------8<------8<------8<------8<------8<------8<------8<---
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char **argv) {
int i;
struct sockaddr_in localport;
char lsof[80];
localport.sin_family = AF_INET;
localport.sin_port = htons(rand() % (65536-1024) + 1024);
localport.sin_addr.s_addr = htonl(INADDR_ANY);
for (i = 1; i < argc; i++) {
struct hostent *hep;
int s;
struct sockaddr_in remoteport;
int val = 1;
s = socket(PF_INET, SOCK_STREAM, 0);
if (s == -1) {
fprintf(stderr, "%s: cannot create socket: %s\n",
argv[0], strerror(errno));
continue;
}
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val) == -1) {
fprintf(stderr, "%s: cannot set SO_REUSEADDR on socket: %s\n",
argv[0], strerror(errno));
continue;
}
if (bind(s, (struct sockaddr *)&localport, sizeof(localport)) == -1) {
fprintf(stderr, "%s: cannot bind to socket: %s\n",
argv[0], strerror(errno));
continue;
}
hep = gethostbyname(argv[i]);
if (!hep) {
fprintf(stderr, "%s: cannot resolve %s: %s\n",
argv[0], argv[i], hstrerror(h_errno));
continue;
}
remoteport.sin_family = AF_INET;
remoteport.sin_port = htons(80);
memcpy(&remoteport.sin_addr, hep->h_addr, hep->h_length);
fprintf(stderr, "%s: %s resolved to: %s\n",
argv[0], argv[i], inet_ntoa(remoteport.sin_addr));
if (connect(s, (struct sockaddr *)&remoteport, sizeof(remoteport)) == -1) {
fprintf(stderr, "%s: cannot connect to %s:80: %s\n",
argv[0], argv[i], strerror(errno));
continue;
}
}
snprintf(lsof, sizeof(lsof), "lsof -p %d", getpid());
system(lsof);
return 0;
}
---8<------8<------8<------8<------8<------8<------8<------8<---
As you can see it only needs an explicit bind and setsockopt call for
each connection.
A test run prints something like:
% ./test-client-same-port www.hjp.at www.wsr.ac.at www.develooper.com
./test-client-same-port: www.hjp.at resolved to: 143.130.50.122
./test-client-same-port: www.wsr.ac.at resolved to: 143.130.16.131
./test-client-same-port: www.develooper.com resolved to: 63.251.223.170
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
[...]
test-clie 348 hjp 3u IPv4 35579 TCP
yoyo.hjp.at:18791->asherah.wsr.ac.at:http (ESTABLISHED)
test-clie 348 hjp 4u IPv4 35582 TCP
yoyo.hjp.at:18791->www.wsr.ac.at:http (ESTABLISHED)
test-clie 348 hjp 5u IPv4 35585 TCP
yoyo.hjp.at:18791->x1.develooper.com:http (ESTABLISHED)
Both port numbers are the same for all three connections.
> Anyway, bringing it all vaguely back on topic, the point of the tarpit is not
> so much as to tie up the resources for an inactive socket, but to chew up the
> limited upstream bandwidth of trojan DSPAM clients on asymmetric connections,
SMTP tarpits as originally designed use very little bandwidth, and most
of that from the server to the client.
hp
--
_ | Peter J. Holzer | I think we need two definitions:
|_|_) | Sysadmin WSR | 1) The problem the *users* want us to solve
| | | [EMAIL PROTECTED] | 2) The problem our solution addresses.
__/ | http://www.hjp.at/ | -- Phillip Hallam-Baker on spam
pgp00000.pgp
Description: PGP signature
