diff options
Diffstat (limited to 'ot_udp.c')
-rw-r--r-- | ot_udp.c | 265 |
1 files changed, 137 insertions, 128 deletions
@@ -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 |
24 | static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff }; | 25 | static const uint8_t g_static_connid[8] = { 0x23, 0x42, 0x05, 0x17, 0xde, 0x41, 0x50, 0xff }; |
25 | #endif | 26 | #endif |
26 | static uint32_t g_rijndael_round_key[44] = {0}; | 27 | static uint32_t g_rijndael_round_key[44] = {0}; |
27 | static uint32_t g_key_of_the_hour[2] = {0}; | 28 | static uint32_t g_key_of_the_hour[2] = {0}; |
28 | static ot_time g_hour_of_the_key; | 29 | static ot_time g_hour_of_the_key; |
29 | 30 | ||
30 | static void udp_generate_rijndael_round_key() { | 31 | static 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 */ |
51 | static void udp_make_connectionid( uint32_t connid[2], const ot_ip6 remoteip, int age ) { | 52 | static 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 */ |
72 | int handle_udp6( int64 serversocket, struct ot_workstruct *ws ) { | 74 | int 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 | ||
194 | static void* udp_worker( void * args ) { | 205 | static 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 | ||
216 | void udp_init( int64 sock, unsigned int worker_count ) { | 227 | void 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 | |||
227 | const char *g_version_udp_c = "$Source$: $Revision$\n"; | ||