• private stuff from ocbMaurice

    Some thoughts about the edonkey network

    Since there are many discussions on how many damage the bot made to the network and so on, I want to show you what all the donkey servers do all day long. I know that this normally needs understanding in tcp/ip behavior but I want to try to write that so everyone can understand why features like the “global extended search” or “server hopping” can decrease the ability of the donkey network.

    As you may know every server waits for connections on two different ports. First we have tcp port 4661 that handles all direct connections from clients to that server. A client just uses tcp connections with the server it is directly connected. For all connections to other servers the client will use udp on port 4665. This lays in the nature of tcp/ip. With tcp connections every submit must be acknowledged by the peer until we can send more data (we can see this if we have a too high upload -> download can no longer be accepted since we use our upload for other things). Udp is handled much more easier; it does not ensure that the peer does get the data we sent. I would say udp is like “would be nice if he gets it but I do not really care” … so if the server is overloaded on the other side the packet gets dropped from the buffer and the dserver application never recieves your request. Udp is often used for online games where it doesn’t make sense to resend an action you did one second before ! It would be far to much to tell the real difference between udp and tcp, if you want so you can read some specifications or look up google.

    client login

    So if we have an incoming tcp connection on the server this will be a user that wants to login (or is allready logged in). The client that wants to login will first send 6 bytes with its ip and its port to the server. If the server is at it’s maximum user limits you will recieve a connection refused. If the server is still alive but the dserver process cannot do as much as he wants, you may wait forever “on queue” (the OS accepted your connection but application is out of reach). If everything goes fine the server will accept your info and the login is proceeded. The server now tries to open a connection to the ip/port the client gave him. If the server successfully can open a connection to your client you get a high id, otherwise the server assigns you one of its internal “firewalled” ids. The server now sends this ID to your client. If your client gets another ID than it had before the message “your ID has changed” will occur.

    The server will now sends its name, description, serverlist and actual users/files. Then you submit your shared files and they get added to this servers fileindex.

    clients and servers

    The connection is now open and you can search on that server or get other sources for your downloads. The connection stays open until either the host or the peer does actively disconnect. If one end just dies without sending a close signal, the other end will think the connection is ok as long as he doesn’t try to communicate with that socket, ie. when you just want to upload, your client will not recognise when the server it is connected to dies (just if that server admin does a clean exit with the server software a close sig is sended). That is normal tcp behavior and cannot be avoided (just if the client would have an intervall to check the connected server!).

    Actually we can perform the same tasks on udp and on tcp (but with tcp we can just communicate with “our” server). Green indicates that data is downloaded and red is for uploads (seen from server side).

    source requests

    • One bytes tells its an edonkey packet,
    • the next byte tells that it is a source request
    • fallowed by 16 bytes with the hash ID.
    • The server answers with number of sources (2 bytes)
    • and the source ip/port (6 bytes) … repeated for every client

    the search request (this is complicated since clients can define several special search cases)

    • One bytes to tell its an edonkey packet,
    • the next byte tells that it is a search request
    • fallowed by all search attributes.
    • for every file match we send
    • all file attributes (filename, hash, id3tags, codec, length, etc.)

    the stats request

    • One bytes to tell its an edonkey packet,
    • the next byte tells that it is a stat request
    • server sends answer with users and files

    the detail request

    • One bytes to tell its an edonkey packet,
    • the next byte tells that it is a detail request
    • server sends answer with name and description

    the list request

    • One bytes to tell its an edonkey packet,
    • the next byte tells that it is a list request
    • The server answers with number of servers (1 byte)
    • and the server ip/port (6 bytes) … repeated for every server


    connection ussage by commands

    request uploads downloads overhead
    search filename, hash(16 bytes), various attributes (for each file match) search request 2 bytes + 5 bytes every attribute
    login id (4 bytes), welcome message
    + stats, details and serverlist
    shared files (like search result) ~10 bytes
    source hash (16 bytes) ip/port * sources (6 bytes each) 2 bytes
    stats users and files (10 bytes) none 2 bytes
    details name and description none 6 bytes
    serverlist ip/port * servers (6 bytes each) none 4 bytes

    a word about low ids

    Every server checks every client if he (the server) can connect to the connecting client. This is done to ensure that other clients can connect to this source, if the server can not it would be useless to give this source id to another client since he will fail to connect to him. So if the server can’t connect directly to the client he assigns a low id to this client.

    Later any client will ask this server for sources on a file the firewalled user shares … so the server sends the answer to this client “user 123 on server x.x.x.x:4661 has that file”. The client now asks this server again and says “y.y.y.y:4662 wants to speak to user 123” … the server now tells “his” user 123 (*) that he should open a connection to y.y.y.y:4662 … the firewalled client will now open a connection to y.y.y.y:4662 and says hello, the other client then can tell him that he would like to download file z etc. This is the only way to beable to connect to a firewalled user, without servers nobody will ever be able to connect to a “firewalled” user.

    That’s the reason why two firewalled users will never be able to make a direct connection to eachother. Everyones firewall will block the other one from opening a connection.


    We can see that search needs the most upload capacity … also does a search need the most cpu on a server; normally a server will use an index for all known md4 hashes since this doesn’t use that much RAM and requests for sources can be completetd without looking up the whole memory, the results come directly from a stack. The Filelist is not that easy to “index” (altough there is some sort of) so we need to look up the whole file index and every file result can easy become larger than 100-200 bytes. mp3s will normally return serveral id3tags (title, album, artist) so these results use far more bytes per file … so a search on mp3s with 200 reults can give 50-100kBytes. On a normal line with 128kbps upload you need the full capacity for about 5-10 second … with 50 kiloBytes you can send out over 5000 source ips/ports to other clients !

    The server hopping is in my eyes not the biggest problem for the servers, they should be able to handle the additional download (users sharing many files) since most servers are on asynchronous lines so they can download much more than upload. But it takes cpu-time on the server to parse the new files and adding them to the index. But this is a problem for firewalled users because they are just “available” when connected to a server.

    appendix 😉

    (*) Any firewall will just block incoming traffic (ie. a user tries to connect to your edonkey). If you open a connection from inside the firewall to some server (webserver, donkey, etc), that server can send back through the connection you opened. You really just need to open/forward port 4662 for your client.

    linux router/firewall configuration for client and server

    all these settings are based on ipchains and ipmasqadm, they are obsolete with kernel 2.4 and new iptables2 … so I would have to look into this sometime. But it should show what you have to do to get all traffic travelling correctly.

    port forwarding for clients
    ipmasqadm autofw -A -r tcp 4662 4662 -h 192.168.0.x
    chain incoming (policy DENY)
    ipchains -A input -p tcp –destination-port 4662 -j ACCEPT
    chain outgoing (policy ACCEPT)

    complete firewall rules for a client
    chain incoming (policy DENY)
    ipchains -A input -p tcp –destination-port 4662 -j ACCEPT
    chain outgoing (policy ACCEPT)

    port forwarding for server
    ipmasqadm autofw -A -r tcp 4661 4661 -h 192.168.0.x
    ipmasqadm autofw -A -r udp 4665 4665 -h 192.168.0.x
    chain incoming (policy DENY)
    ipchains -A input -p tcp –destination-port 4661 -j ACCEPT
    ipchains -A input -p udp –destination-port 4665 -j ACCEPT
    chain outgoing (policy ACCEPT)

    complete firewall rules for a server
    chain incoming (policy DENY)
    ipchains -A input -p tcp –destination-port 4661 -j ACCEPT
    ipchains -A input -p udp –destination-port 4665 -j ACCEPT
    chain outgoing (policy ACCEPT)

    you cannot DENY output, even if you set “allow tcp-source-port 4662” and “udp-source-port 4665” … then your server could send data, but the id check goes with a new socket so you have a new source-port, it would result in a working server but assigning low ids to all users !

Comments are closed.