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