1 /* This software was written by Dirk Engling <erdgeist@erdgeist.org>
2 It is considered beerware. Prost. Skol. Cheers or whatever.
19 #include "ot_rijndael.h"
22 #include "trackerlogic.h"
25 static const uint8_t g_static_connid
[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff };
27 static uint32_t g_rijndael_round_key
[44] = {0};
28 static uint32_t g_key_of_the_hour
[2] = {0};
29 static ot_time g_hour_of_the_key
;
31 static void udp_generate_rijndael_round_key() {
33 #ifdef WANT_ARC4RANDOM
34 arc4random_buf(&key
[0], sizeof(key
));
41 rijndaelKeySetupEnc128(g_rijndael_round_key
, (uint8_t *)key
);
43 #ifdef WANT_ARC4RANDOM
44 g_key_of_the_hour
[0] = arc4random();
46 g_key_of_the_hour
[0] = random();
48 g_hour_of_the_key
= g_now_minutes
;
51 /* Generate current and previous connection id for ip */
52 static void udp_make_connectionid(uint32_t connid
[2], const ot_ip6 remoteip
, int age
) {
53 uint32_t plain
[4], crypt
[4];
55 if (g_now_minutes
+ 60 > g_hour_of_the_key
) {
56 g_hour_of_the_key
= g_now_minutes
;
57 g_key_of_the_hour
[1] = g_key_of_the_hour
[0];
58 #ifdef WANT_ARC4RANDOM
59 g_key_of_the_hour
[0] = arc4random();
61 g_key_of_the_hour
[0] = random();
65 memcpy(plain
, remoteip
, sizeof(plain
));
66 for (i
= 0; i
< 4; ++i
)
67 plain
[i
] ^= g_key_of_the_hour
[age
];
68 rijndaelEncrypt128(g_rijndael_round_key
, (uint8_t *)remoteip
, (uint8_t *)crypt
);
69 connid
[0] = crypt
[0] ^ crypt
[1];
70 connid
[1] = crypt
[2] ^ crypt
[3];
73 /* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */
74 int handle_udp6(int64 serversocket
, struct ot_workstruct
*ws
) {
76 uint32_t *inpacket
= (uint32_t *)ws
->inbuf
;
77 uint32_t *outpacket
= (uint32_t *)ws
->outbuf
;
78 uint32_t left
, event
, scopeid
;
81 uint16_t port
, remoteport
;
82 size_t byte_count
, scrape_count
;
84 byte_count
= socket_recv6(serversocket
, ws
->inbuf
, G_INBUF_SIZE
, remoteip
, &remoteport
, &scopeid
);
88 stats_issue_event(EVENT_ACCEPT
, FLAG_UDP
, (uintptr_t)remoteip
);
89 stats_issue_event(EVENT_READ
, FLAG_UDP
, byte_count
);
91 /* Minimum udp tracker packet size, also catches error */
95 /* Get action to take. Ignore error messages and broken packets */
96 action
= ntohl(inpacket
[2]);
100 /* Generate the connection id we give out and expect to and from
101 the requesting ip address, this prevents udp spoofing */
102 udp_make_connectionid(connid
, remoteip
, 0);
104 /* Initialise hash pointer */
108 /* If action is not 0 (connect), then we expect the derived
109 connection id in first 64 bit */
110 if ((action
> 0) && (inpacket
[0] != connid
[0] || inpacket
[1] != connid
[1])) {
111 /* If connection id does not match, try the one that was
112 valid in the previous hour. Only if this also does not
113 match, return an error packet */
114 udp_make_connectionid(connid
, remoteip
, 1);
115 if (inpacket
[0] != connid
[0] || inpacket
[1] != connid
[1]) {
116 const size_t s
= sizeof("Connection ID missmatch.");
117 outpacket
[0] = htonl(3);
118 outpacket
[1] = inpacket
[3];
119 memcpy(&outpacket
[2], "Connection ID missmatch.", s
);
120 socket_send6(serversocket
, ws
->outbuf
, 8 + s
, remoteip
, remoteport
, 0);
121 stats_issue_event(EVENT_CONNID_MISSMATCH
, FLAG_UDP
, 8 + s
);
127 case 0: /* This is a connect action */
128 /* look for udp bittorrent magic id */
129 if ((ntohl(inpacket
[0]) != 0x00000417) || (ntohl(inpacket
[1]) != 0x27101980))
133 outpacket
[1] = inpacket
[3];
134 outpacket
[2] = connid
[0];
135 outpacket
[3] = connid
[1];
137 socket_send6(serversocket
, ws
->outbuf
, 16, remoteip
, remoteport
, 0);
138 stats_issue_event(EVENT_CONNECT
, FLAG_UDP
, 16);
140 case 1: /* This is an announce action */
141 /* Minimum udp announce packet size */
145 /* We do only want to know, if it is zero */
146 left
= inpacket
[64 / 4] | inpacket
[68 / 4];
148 event
= ntohl(inpacket
[80 / 4]);
149 port
= *(uint16_t *)(((char *)inpacket
) + 96);
150 ws
->hash
= (ot_hash
*)(((char *)inpacket
) + 16);
152 OT_SETIP(ws
->peer
, remoteip
);
153 OT_SETPORT(ws
->peer
, &port
);
154 OT_PEERFLAG(ws
->peer
) = 0;
158 OT_PEERFLAG(ws
->peer
) |= PEER_FLAG_COMPLETED
;
161 OT_PEERFLAG(ws
->peer
) |= PEER_FLAG_STOPPED
;
168 OT_PEERFLAG(ws
->peer
) |= PEER_FLAG_SEEDING
;
170 outpacket
[0] = htonl(1); /* announce action */
171 outpacket
[1] = inpacket
[12 / 4];
173 if (OT_PEERFLAG(ws
->peer
) & PEER_FLAG_STOPPED
) { /* Peer is gone. */
174 ws
->reply
= ws
->outbuf
;
175 ws
->reply_size
= remove_peer_from_torrent(FLAG_UDP
, ws
);
177 /* Limit amount of peers to OT_MAX_PEERS_UDP */
178 uint32_t numwant
= ntohl(inpacket
[92 / 4]);
179 size_t max_peers
= ip6_isv4mapped(remoteip
) ? OT_MAX_PEERS_UDP4
: OT_MAX_PEERS_UDP6
;
180 if (numwant
> max_peers
)
183 ws
->reply
= ws
->outbuf
+ 8;
184 ws
->reply_size
= 8 + add_peer_to_torrent_and_return_peers(FLAG_UDP
, ws
, numwant
);
187 socket_send6(serversocket
, ws
->outbuf
, ws
->reply_size
, remoteip
, remoteport
, 0);
188 stats_issue_event(EVENT_ANNOUNCE
, FLAG_UDP
, ws
->reply_size
);
191 case 2: /* This is a scrape action */
192 outpacket
[0] = htonl(2); /* scrape action */
193 outpacket
[1] = inpacket
[12 / 4];
195 for (scrape_count
= 0; (scrape_count
* 20 < byte_count
- 16) && (scrape_count
<= 74); scrape_count
++)
196 return_udp_scrape_for_torrent(*(ot_hash
*)(((char *)inpacket
) + 16 + 20 * scrape_count
), ((char *)outpacket
) + 8 + 12 * scrape_count
);
198 socket_send6(serversocket
, ws
->outbuf
, 8 + 12 * scrape_count
, remoteip
, remoteport
, 0);
199 stats_issue_event(EVENT_SCRAPE
, FLAG_UDP
, scrape_count
);
205 static void *udp_worker(void *args
) {
206 int64 sock
= (int64
)args
;
207 struct ot_workstruct ws
;
208 memset(&ws
, 0, sizeof(ws
));
210 ws
.inbuf
= malloc(G_INBUF_SIZE
);
211 ws
.outbuf
= malloc(G_OUTBUF_SIZE
);
212 #ifdef _DEBUG_HTTPERROR
213 ws
.debugbuf
= malloc(G_DEBUGBUF_SIZE
);
216 while (g_opentracker_running
)
217 handle_udp6(sock
, &ws
);
221 #ifdef _DEBUG_HTTPERROR
227 void udp_init(int64 sock
, unsigned int worker_count
) {
229 if (!g_rijndael_round_key
[0])
230 udp_generate_rijndael_round_key();
232 fprintf(stderr
, " installing %d workers on udp socket %ld\n", worker_count
, (unsigned long)sock
);
234 while (worker_count
--)
235 pthread_create(&thread_id
, NULL
, udp_worker
, (void *)sock
);