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