summaryrefslogtreecommitdiff
path: root/ot_udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_udp.c')
-rw-r--r--ot_udp.c265
1 files changed, 137 insertions, 128 deletions
diff --git a/ot_udp.c b/ot_udp.c
index edbaca8..97ccd38 100644
--- a/ot_udp.c
+++ b/ot_udp.c
@@ -4,30 +4,31 @@
4 $id$ */ 4 $id$ */
5 5
6/* System */ 6/* System */
7#include <stdlib.h>
8#include <pthread.h>
9#include <string.h>
10#include <arpa/inet.h> 7#include <arpa/inet.h>
8#include <pthread.h>
11#include <stdio.h> 9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12 12
13/* Libowfat */ 13/* Libowfat */
14#include "socket.h"
15#include "io.h" 14#include "io.h"
15#include "ip6.h"
16#include "socket.h"
16 17
17/* Opentracker */ 18/* Opentracker */
18#include "trackerlogic.h"
19#include "ot_udp.h"
20#include "ot_stats.h"
21#include "ot_rijndael.h" 19#include "ot_rijndael.h"
20#include "ot_stats.h"
21#include "ot_udp.h"
22#include "trackerlogic.h"
22 23
23#if 0 24#if 0
24static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff }; 25static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff };
25#endif 26#endif
26static uint32_t g_rijndael_round_key[44] = {0}; 27static uint32_t g_rijndael_round_key[44] = {0};
27static uint32_t g_key_of_the_hour[2] = {0}; 28static uint32_t g_key_of_the_hour[2] = {0};
28static ot_time g_hour_of_the_key; 29static ot_time g_hour_of_the_key;
29 30
30static void udp_generate_rijndael_round_key() { 31static void udp_generate_rijndael_round_key() {
31 uint32_t key[16]; 32 uint32_t key[16];
32#ifdef WANT_ARC4RANDOM 33#ifdef WANT_ARC4RANDOM
33 arc4random_buf(&key[0], sizeof(key)); 34 arc4random_buf(&key[0], sizeof(key));
@@ -37,7 +38,7 @@ static void udp_generate_rijndael_round_key() {
37 key[2] = random(); 38 key[2] = random();
38 key[3] = random(); 39 key[3] = random();
39#endif 40#endif
40 rijndaelKeySetupEnc128( g_rijndael_round_key, (uint8_t*)key ); 41 rijndaelKeySetupEnc128(g_rijndael_round_key, (uint8_t *)key);
41 42
42#ifdef WANT_ARC4RANDOM 43#ifdef WANT_ARC4RANDOM
43 g_key_of_the_hour[0] = arc4random(); 44 g_key_of_the_hour[0] = arc4random();
@@ -48,180 +49,188 @@ static void udp_generate_rijndael_round_key() {
48} 49}
49 50
50/* Generate current and previous connection id for ip */ 51/* Generate current and previous connection id for ip */
51static void udp_make_connectionid( uint32_t connid[2], const ot_ip6 remoteip, int age ) { 52static void udp_make_connectionid(uint32_t connid[2], const ot_ip6 remoteip, int age) {
52 uint32_t plain[4], crypt[4]; 53 uint32_t plain[4], crypt[4];
53 int i; 54 int i;
54 if( g_now_minutes + 60 > g_hour_of_the_key ) { 55 if (g_now_minutes + 60 > g_hour_of_the_key) {
55 g_hour_of_the_key = g_now_minutes; 56 g_hour_of_the_key = g_now_minutes;
56 g_key_of_the_hour[1] = g_key_of_the_hour[0]; 57 g_key_of_the_hour[1] = g_key_of_the_hour[0];
57#ifdef WANT_ARC4RANDOM 58#ifdef WANT_ARC4RANDOM
58 g_key_of_the_hour[0] = arc4random(); 59 g_key_of_the_hour[0] = arc4random();
59#else 60#else
60 g_key_of_the_hour[0] = random(); 61 g_key_of_the_hour[0] = random();
61#endif 62#endif
62 } 63 }
63 64
64 memcpy( plain, remoteip, sizeof( plain ) ); 65 memcpy(plain, remoteip, sizeof(plain));
65 for( i=0; i<4; ++i ) plain[i] ^= g_key_of_the_hour[age]; 66 for (i = 0; i < 4; ++i)
66 rijndaelEncrypt128( g_rijndael_round_key, (uint8_t*)remoteip, (uint8_t*)crypt ); 67 plain[i] ^= g_key_of_the_hour[age];
68 rijndaelEncrypt128(g_rijndael_round_key, (uint8_t *)remoteip, (uint8_t *)crypt);
67 connid[0] = crypt[0] ^ crypt[1]; 69 connid[0] = crypt[0] ^ crypt[1];
68 connid[1] = crypt[2] ^ crypt[3]; 70 connid[1] = crypt[2] ^ crypt[3];
69} 71}
70 72
71/* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */ 73/* UDP implementation according to http://xbtt.sourceforge.net/udp_tracker_protocol.html */
72int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) { 74int handle_udp6(int64 serversocket, struct ot_workstruct *ws) {
73 ot_ip6 remoteip; 75 ot_ip6 remoteip;
74 uint32_t *inpacket = (uint32_t*)ws->inbuf; 76 uint32_t *inpacket = (uint32_t *)ws->inbuf;
75 uint32_t *outpacket = (uint32_t*)ws->outbuf; 77 uint32_t *outpacket = (uint32_t *)ws->outbuf;
76 uint32_t numwant, left, event, scopeid; 78 uint32_t left, event, scopeid;
77 uint32_t connid[2]; 79 uint32_t connid[2];
78 uint32_t action; 80 uint32_t action;
79 uint16_t port, remoteport; 81 uint16_t port, remoteport;
80 size_t byte_count, scrape_count; 82 size_t byte_count, scrape_count;
81 83
82 byte_count = socket_recv6( serversocket, ws->inbuf, G_INBUF_SIZE, remoteip, &remoteport, &scopeid ); 84 byte_count = socket_recv6(serversocket, ws->inbuf, G_INBUF_SIZE, remoteip, &remoteport, &scopeid);
83 if( !byte_count ) return 0; 85 if (!byte_count)
84 86 return 0;
85 stats_issue_event( EVENT_ACCEPT, FLAG_UDP, (uintptr_t)remoteip ); 87
86 stats_issue_event( EVENT_READ, FLAG_UDP, byte_count ); 88 stats_issue_event(EVENT_ACCEPT, FLAG_UDP, (uintptr_t)remoteip);
89 stats_issue_event(EVENT_READ, FLAG_UDP, byte_count);
87 90
88 /* Minimum udp tracker packet size, also catches error */ 91 /* Minimum udp tracker packet size, also catches error */
89 if( byte_count < 16 ) 92 if (byte_count < 16)
90 return 1; 93 return 1;
91 94
92 /* Get action to take. Ignore error messages and broken packets */ 95 /* Get action to take. Ignore error messages and broken packets */
93 action = ntohl( inpacket[2] ); 96 action = ntohl(inpacket[2]);
94 if( action > 2 ) 97 if (action > 2)
95 return 1; 98 return 1;
96 99
97 /* Generate the connection id we give out and expect to and from 100 /* Generate the connection id we give out and expect to and from
98 the requesting ip address, this prevents udp spoofing */ 101 the requesting ip address, this prevents udp spoofing */
99 udp_make_connectionid( connid, remoteip, 0 ); 102 udp_make_connectionid(connid, remoteip, 0);
100 103
101 /* Initialise hash pointer */ 104 /* Initialise hash pointer */
102 ws->hash = NULL; 105 ws->hash = NULL;
103 ws->peer_id = NULL; 106 ws->peer_id = NULL;
104 107
105 /* If action is not 0 (connect), then we expect the derived 108 /* If action is not 0 (connect), then we expect the derived
106 connection id in first 64 bit */ 109 connection id in first 64 bit */
107 if( ( action > 0 ) && ( inpacket[0] != connid[0] || inpacket[1] != connid[1] ) ) { 110 if ((action > 0) && (inpacket[0] != connid[0] || inpacket[1] != connid[1])) {
108 /* If connection id does not match, try the one that was 111 /* If connection id does not match, try the one that was
109 valid in the previous hour. Only if this also does not 112 valid in the previous hour. Only if this also does not
110 match, return an error packet */ 113 match, return an error packet */
111 udp_make_connectionid( connid, remoteip, 1 ); 114 udp_make_connectionid(connid, remoteip, 1);
112 if( inpacket[0] != connid[0] || inpacket[1] != connid[1] ) { 115 if (inpacket[0] != connid[0] || inpacket[1] != connid[1]) {
113 const size_t s = sizeof( "Connection ID missmatch." ); 116 const size_t s = sizeof("Connection ID missmatch.");
114 outpacket[0] = htonl( 3 ); outpacket[1] = inpacket[3]; 117 outpacket[0] = htonl(3);
115 memcpy( &outpacket[2], "Connection ID missmatch.", s ); 118 outpacket[1] = inpacket[3];
116 socket_send6( serversocket, ws->outbuf, 8 + s, remoteip, remoteport, 0 ); 119 memcpy(&outpacket[2], "Connection ID missmatch.", s);
117 stats_issue_event( EVENT_CONNID_MISSMATCH, FLAG_UDP, 8 + s ); 120 socket_send6(serversocket, ws->outbuf, 8 + s, remoteip, remoteport, 0);
121 stats_issue_event(EVENT_CONNID_MISSMATCH, FLAG_UDP, 8 + s);
118 return 1; 122 return 1;
119 } 123 }
120 } 124 }
121 125
122 switch( action ) { 126 switch (action) {
123 case 0: /* This is a connect action */ 127 case 0: /* This is a connect action */
124 /* look for udp bittorrent magic id */ 128 /* look for udp bittorrent magic id */
125 if( (ntohl(inpacket[0]) != 0x00000417) || (ntohl(inpacket[1]) != 0x27101980) ) 129 if ((ntohl(inpacket[0]) != 0x00000417) || (ntohl(inpacket[1]) != 0x27101980))
126 return 1; 130 return 1;
131
132 outpacket[0] = 0;
133 outpacket[1] = inpacket[3];
134 outpacket[2] = connid[0];
135 outpacket[3] = connid[1];
136
137 socket_send6(serversocket, ws->outbuf, 16, remoteip, remoteport, 0);
138 stats_issue_event(EVENT_CONNECT, FLAG_UDP, 16);
139 break;
140 case 1: /* This is an announce action */
141 /* Minimum udp announce packet size */
142 if (byte_count < 98)
143 return 1;
144
145 /* We do only want to know, if it is zero */
146 left = inpacket[64 / 4] | inpacket[68 / 4];
127 147
128 outpacket[0] = 0; 148 event = ntohl(inpacket[80 / 4]);
129 outpacket[1] = inpacket[3]; 149 port = *(uint16_t *)(((char *)inpacket) + 96);
130 outpacket[2] = connid[0]; 150 ws->hash = (ot_hash *)(((char *)inpacket) + 16);
131 outpacket[3] = connid[1];
132 151
133 socket_send6( serversocket, ws->outbuf, 16, remoteip, remoteport, 0 ); 152 OT_SETIP(ws->peer, remoteip);
134 stats_issue_event( EVENT_CONNECT, FLAG_UDP, 16 ); 153 OT_SETPORT(ws->peer, &port);
154 OT_PEERFLAG(ws->peer) = 0;
155
156 switch (event) {
157 case 1:
158 OT_PEERFLAG(ws->peer) |= PEER_FLAG_COMPLETED;
159 break;
160 case 3:
161 OT_PEERFLAG(ws->peer) |= PEER_FLAG_STOPPED;
135 break; 162 break;
136 case 1: /* This is an announce action */ 163 default:
137 /* Minimum udp announce packet size */
138 if( byte_count < 98 )
139 return 1;
140
141 /* We do only want to know, if it is zero */
142 left = inpacket[64/4] | inpacket[68/4];
143
144 /* Limit amount of peers to 200 */
145 numwant = ntohl( inpacket[92/4] );
146 if (numwant > 200) numwant = 200;
147
148 event = ntohl( inpacket[80/4] );
149 port = *(uint16_t*)( ((char*)inpacket) + 96 );
150 ws->hash = (ot_hash*)( ((char*)inpacket) + 16 );
151
152 OT_SETIP( &ws->peer, remoteip );
153 OT_SETPORT( &ws->peer, &port );
154 OT_PEERFLAG( &ws->peer ) = 0;
155
156 switch( event ) {
157 case 1: OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_COMPLETED; break;
158 case 3: OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED; break;
159 default: break;
160 }
161
162 if( !left )
163 OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_SEEDING;
164
165 outpacket[0] = htonl( 1 ); /* announce action */
166 outpacket[1] = inpacket[12/4];
167
168 if( OT_PEERFLAG( &ws->peer ) & PEER_FLAG_STOPPED ) { /* Peer is gone. */
169 ws->reply = ws->outbuf;
170 ws->reply_size = remove_peer_from_torrent( FLAG_UDP, ws );
171 } else {
172 ws->reply = ws->outbuf + 8;
173 ws->reply_size = 8 + add_peer_to_torrent_and_return_peers( FLAG_UDP, ws, numwant );
174 }
175
176 socket_send6( serversocket, ws->outbuf, ws->reply_size, remoteip, remoteport, 0 );
177 stats_issue_event( EVENT_ANNOUNCE, FLAG_UDP, ws->reply_size );
178 break; 164 break;
165 }
179 166
180 case 2: /* This is a scrape action */ 167 if (!left)
181 outpacket[0] = htonl( 2 ); /* scrape action */ 168 OT_PEERFLAG(ws->peer) |= PEER_FLAG_SEEDING;
182 outpacket[1] = inpacket[12/4];
183 169
184 for( scrape_count = 0; ( scrape_count * 20 < byte_count - 16) && ( scrape_count <= 74 ); scrape_count++ ) 170 outpacket[0] = htonl(1); /* announce action */
185 return_udp_scrape_for_torrent( *(ot_hash*)( ((char*)inpacket) + 16 + 20 * scrape_count ), ((char*)outpacket) + 8 + 12 * scrape_count ); 171 outpacket[1] = inpacket[12 / 4];
186 172
187 socket_send6( serversocket, ws->outbuf, 8 + 12 * scrape_count, remoteip, remoteport, 0 ); 173 if (OT_PEERFLAG(ws->peer) & PEER_FLAG_STOPPED) { /* Peer is gone. */
188 stats_issue_event( EVENT_SCRAPE, FLAG_UDP, scrape_count ); 174 ws->reply = ws->outbuf;
189 break; 175 ws->reply_size = remove_peer_from_torrent(FLAG_UDP, ws);
176 } else {
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)
181 numwant = max_peers;
182
183 ws->reply = ws->outbuf + 8;
184 ws->reply_size = 8 + add_peer_to_torrent_and_return_peers(FLAG_UDP, ws, numwant);
185 }
186
187 socket_send6(serversocket, ws->outbuf, ws->reply_size, remoteip, remoteport, 0);
188 stats_issue_event(EVENT_ANNOUNCE, FLAG_UDP, ws->reply_size);
189 break;
190
191 case 2: /* This is a scrape action */
192 outpacket[0] = htonl(2); /* scrape action */
193 outpacket[1] = inpacket[12 / 4];
194
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);
197
198 socket_send6(serversocket, ws->outbuf, 8 + 12 * scrape_count, remoteip, remoteport, 0);
199 stats_issue_event(EVENT_SCRAPE, FLAG_UDP, scrape_count);
200 break;
190 } 201 }
191 return 1; 202 return 1;
192} 203}
193 204
194static void* udp_worker( void * args ) { 205static void *udp_worker(void *args) {
195 int64 sock = (int64)args; 206 int64 sock = (int64)args;
196 struct ot_workstruct ws; 207 struct ot_workstruct ws;
197 memset( &ws, 0, sizeof(ws) ); 208 memset(&ws, 0, sizeof(ws));
198 209
199 ws.inbuf=malloc(G_INBUF_SIZE); 210 ws.inbuf = malloc(G_INBUF_SIZE);
200 ws.outbuf=malloc(G_OUTBUF_SIZE); 211 ws.outbuf = malloc(G_OUTBUF_SIZE);
201#ifdef _DEBUG_HTTPERROR 212#ifdef _DEBUG_HTTPERROR
202 ws.debugbuf=malloc(G_DEBUGBUF_SIZE); 213 ws.debugbuf = malloc(G_DEBUGBUF_SIZE);
203#endif 214#endif
204 215
205 while( g_opentracker_running ) 216 while (g_opentracker_running)
206 handle_udp6( sock, &ws ); 217 handle_udp6(sock, &ws);
207 218
208 free( ws.inbuf ); 219 free(ws.inbuf);
209 free( ws.outbuf ); 220 free(ws.outbuf);
210#ifdef _DEBUG_HTTPERROR 221#ifdef _DEBUG_HTTPERROR
211 free( ws.debugbuf ); 222 free(ws.debugbuf);
212#endif 223#endif
213 return NULL; 224 return NULL;
214} 225}
215 226
216void udp_init( int64 sock, unsigned int worker_count ) { 227void udp_init(int64 sock, unsigned int worker_count) {
217 pthread_t thread_id; 228 pthread_t thread_id;
218 if( !g_rijndael_round_key[0] ) 229 if (!g_rijndael_round_key[0])
219 udp_generate_rijndael_round_key(); 230 udp_generate_rijndael_round_key();
220#ifdef _DEBUG 231#ifdef _DEBUG
221 fprintf( stderr, " installing %d workers on udp socket %ld\n", worker_count, (unsigned long)sock ); 232 fprintf(stderr, " installing %d workers on udp socket %ld\n", worker_count, (unsigned long)sock);
222#endif 233#endif
223 while( worker_count-- ) 234 while (worker_count--)
224 pthread_create( &thread_id, NULL, udp_worker, (void *)sock ); 235 pthread_create(&thread_id, NULL, udp_worker, (void *)sock);
225} 236}
226
227const char *g_version_udp_c = "$Source$: $Revision$\n";