1 /*
2
3 client_listener.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2007 Pekka Riikonen
8
9 The contents of this file are subject to one of the Licenses specified
10 in the COPYING file; You may not use this file except in compliance
11 with the License.
12
13 The software distributed under the License is distributed on an "AS IS"
14 basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15 KIND, either expressed or implied. See the COPYING file for more
16 information.
17
18 */
19
20 #include "silc.h"
21 #include "silcclient.h"
22 #include "client_internal.h"
23
24 /************************** Types and definitions ***************************/
25
26 /* Listener context */
27 struct SilcClientListenerStruct {
28 SilcClient client; /* Client */
29 SilcSchedule schedule; /* Scheduler */
30 SilcClientConnectCallback callback; /* Connection callback */
31 void *context; /* User context */
32 SilcClientConnectionParams params; /* Connection parameters */
33 SilcPublicKey public_key; /* Responder public key */
34 SilcPrivateKey private_key; /* Responder private key */
35 SilcNetListener tcp_listener; /* TCP listener */
36 SilcPacketStream udp_listener; /* UDP listener */
37 };
38
39 /************************ Static utility functions **************************/
40
41 /* Called after application has verified remote host's public key. */
42
silc_client_listener_verify_key_cb(SilcBool success,void * context)43 static void silc_client_listener_verify_key_cb(SilcBool success, void *context)
44 {
45 SilcVerifyKeyContext verify = context;
46
47 /* Call the completion callback back to the SKE */
48 verify->completion(verify->ske, success ? SILC_SKE_STATUS_OK :
49 SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
50 verify->completion_context);
51
52 silc_free(verify);
53 }
54
55 /* Verify remote host's public key. */
56
57 static void
silc_client_listener_verify_key(SilcSKE ske,SilcPublicKey public_key,void * context,SilcSKEVerifyCbCompletion completion,void * completion_context)58 silc_client_listener_verify_key(SilcSKE ske,
59 SilcPublicKey public_key,
60 void *context,
61 SilcSKEVerifyCbCompletion completion,
62 void *completion_context)
63 {
64 SilcClientConnection conn = context;
65 SilcClient client = conn->client;
66 SilcVerifyKeyContext verify;
67
68 /* If we provided repository for SKE and we got here the key was not
69 found from the repository. */
70 if (conn->internal->params.repository &&
71 !conn->internal->params.verify_notfound) {
72 completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
73 completion_context);
74 return;
75 }
76
77 SILC_LOG_DEBUG(("Verify remote public key"));
78
79 verify = silc_calloc(1, sizeof(*verify));
80 if (!verify) {
81 completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
82 completion_context);
83 return;
84 }
85 verify->ske = ske;
86 verify->completion = completion;
87 verify->completion_context = completion_context;
88
89 /* Verify public key in application */
90 client->internal->ops->verify_public_key(client, conn,
91 SILC_CONN_CLIENT, public_key,
92 silc_client_listener_verify_key_cb,
93 verify);
94 }
95
96 /* Key exchange protocol completion callback. */
97
silc_client_listener_completion(SilcSKE ske,SilcSKEStatus status,SilcSKESecurityProperties prop,SilcSKEKeyMaterial keymat,SilcSKERekeyMaterial rekey,void * context)98 static void silc_client_listener_completion(SilcSKE ske,
99 SilcSKEStatus status,
100 SilcSKESecurityProperties prop,
101 SilcSKEKeyMaterial keymat,
102 SilcSKERekeyMaterial rekey,
103 void *context)
104 {
105 SilcClientConnection conn = context;
106 SilcCipher send_key, receive_key;
107 SilcHmac hmac_send, hmac_receive;
108
109 SILC_LOG_DEBUG(("Key exchange completed"));
110
111 if (status != SILC_SKE_STATUS_OK) {
112 /* Key exchange failed */
113 conn->callback(conn->client, conn,
114 status == SILC_SKE_STATUS_TIMEOUT ?
115 SILC_CLIENT_CONN_ERROR_TIMEOUT :
116 SILC_CLIENT_CONN_ERROR_KE, conn->internal->error,
117 conn->internal->disconnect_message,
118 conn->callback_context);
119 return;
120 }
121
122 /* Allocate the cipher and HMAC contexts */
123 if (!silc_ske_set_keys(ske, keymat, prop, &send_key, &receive_key,
124 &hmac_send, &hmac_receive, &conn->internal->hash)) {
125 conn->callback(conn->client, conn,
126 SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
127 conn->callback_context);
128 return;
129 }
130
131 /* Set the keys into the packet stream. After this call packets will be
132 encrypted with these keys. */
133 if (!silc_packet_set_keys(conn->stream, send_key, receive_key, hmac_send,
134 hmac_receive, FALSE)) {
135 conn->callback(conn->client, conn,
136 SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
137 conn->callback_context);
138 return;
139 }
140
141 /* Key exchange successful */
142 conn->callback(conn->client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
143 conn->callback_context);
144 }
145
146 /* Starts key agreement as responder. */
147
148 static void
silc_client_listener_new_connection(SilcClientListener listener,SilcPacketStream stream)149 silc_client_listener_new_connection(SilcClientListener listener,
150 SilcPacketStream stream)
151 {
152 SilcClient client = listener->client;
153 SilcClientConnection conn;
154 SilcSKEParamsStruct params = {};
155 const char *hostname = NULL, *ip = NULL;
156 SilcUInt16 port;
157
158 /* Get remote information */
159 silc_socket_stream_get_info(silc_packet_stream_get_stream(stream),
160 NULL, &hostname, &ip, &port);
161 if (!ip || !port) {
162 listener->callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL,
163 listener->context);
164 silc_packet_stream_destroy(stream);
165 return;
166 }
167 if (!hostname)
168 hostname = ip;
169
170 /* Add new connection */
171 conn = silc_client_add_connection(client, SILC_CONN_CLIENT, FALSE,
172 &listener->params,
173 listener->public_key,
174 listener->private_key,
175 (char *)hostname, port,
176 listener->callback, listener->context);
177 if (!conn) {
178 listener->callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL,
179 listener->context);
180 silc_packet_stream_destroy(stream);
181 return;
182 }
183 conn->stream = stream;
184 conn->internal->schedule = listener->schedule;
185 silc_packet_set_context(conn->stream, conn);
186
187 SILC_LOG_DEBUG(("Processing new incoming connection %p", conn));
188
189 /* Allocate SKE */
190 conn->internal->ske =
191 silc_ske_alloc(client->rng, conn->internal->schedule,
192 listener->params.repository, listener->public_key,
193 listener->private_key, listener);
194 if (!conn->internal->ske) {
195 conn->callback(conn->client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
196 conn->callback_context);
197 return;
198 }
199
200 /* Set SKE parameters */
201 params.version = client->internal->silc_client_version;
202 params.flags = SILC_SKE_SP_FLAG_MUTUAL;
203 if (listener->params.udp) {
204 params.flags |= SILC_SKE_SP_FLAG_IV_INCLUDED;
205 params.session_port = listener->params.local_port;
206 }
207
208 silc_ske_set_callbacks(conn->internal->ske, silc_client_listener_verify_key,
209 silc_client_listener_completion, conn);
210
211 /* Start key exchange as responder */
212 conn->internal->op = silc_ske_responder(conn->internal->ske,
213 conn->stream, ¶ms);
214 if (!conn->internal->op)
215 conn->callback(conn->client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
216 conn->callback_context);
217 }
218
219 /* TCP network listener callback. Accepts new key agreement connection.
220 Responder function. */
221
silc_client_listener_tcp_accept(SilcNetStatus status,SilcStream stream,void * context)222 static void silc_client_listener_tcp_accept(SilcNetStatus status,
223 SilcStream stream,
224 void *context)
225 {
226 SilcClientListener listener = context;
227 SilcPacketStream packet_stream;
228
229 SILC_LOG_DEBUG(("New incoming TCP connection"));
230
231 /* Create packet stream */
232 packet_stream =
233 silc_packet_stream_create(listener->client->internal->packet_engine,
234 listener->schedule, stream);
235 if (!packet_stream) {
236 silc_stream_destroy(stream);
237 return;
238 }
239
240 /* Process session */
241 silc_client_listener_new_connection(listener, packet_stream);
242 }
243
244 /* UDP network listener callback. Accepts new key agreement session.
245 Responder function. */
246
silc_client_udp_accept(SilcPacketEngine engine,SilcPacketStream stream,SilcPacket packet,void * callback_context,void * stream_context)247 static SilcBool silc_client_udp_accept(SilcPacketEngine engine,
248 SilcPacketStream stream,
249 SilcPacket packet,
250 void *callback_context,
251 void *stream_context)
252 {
253 SilcClientListener listener = callback_context;
254 SilcPacketStream packet_stream;
255 SilcUInt16 port;
256 const char *ip;
257
258 SILC_LOG_DEBUG(("New incoming UDP connection"));
259
260 /* We want only key exchange packet. Eat other packets so that default
261 packet callback doesn't get them. */
262 if (packet->type != SILC_PACKET_KEY_EXCHANGE) {
263 silc_packet_free(packet);
264 return TRUE;
265 }
266
267 /* Create packet stream for this remote UDP session */
268 if (!silc_packet_get_sender(packet, &ip, &port)) {
269 silc_packet_free(packet);
270 return TRUE;
271 }
272 packet_stream = silc_packet_stream_add_remote(stream, ip, port, packet);
273 if (!packet_stream) {
274 silc_packet_free(packet);
275 return TRUE;
276 }
277
278 /* Process session */
279 silc_client_listener_new_connection(listener, packet_stream);
280 return TRUE;
281 }
282
283 /* Packet stream callbacks */
284 static SilcPacketCallbacks silc_client_listener_stream_cb =
285 {
286 silc_client_udp_accept, NULL, NULL
287 };
288
289 /***************************** Listner routines *****************************/
290
291 /* Adds network listener. The `callback' will be called after new conection
292 has arrived and key exchange protocol has been completed. */
293
294 SilcClientListener
silc_client_listener_add(SilcClient client,SilcSchedule schedule,SilcClientConnectionParams * params,SilcPublicKey public_key,SilcPrivateKey private_key,SilcClientConnectCallback callback,void * context)295 silc_client_listener_add(SilcClient client,
296 SilcSchedule schedule,
297 SilcClientConnectionParams *params,
298 SilcPublicKey public_key,
299 SilcPrivateKey private_key,
300 SilcClientConnectCallback callback,
301 void *context)
302 {
303 SilcClientListener listener;
304 SilcStream stream;
305
306 if (!client || !schedule ||
307 !params || (!params->local_ip && !params->bind_ip))
308 return NULL;
309
310 SILC_LOG_DEBUG(("Adding new listener"));
311
312 listener = silc_calloc(1, sizeof(*listener));
313 if (!listener)
314 return NULL;
315 listener->client = client;
316 listener->schedule = schedule;
317 listener->callback = callback;
318 listener->context = context;
319 listener->params = *params;
320 listener->public_key = public_key;
321 listener->private_key = private_key;
322
323 /* Create network listener */
324 if (params->udp) {
325 /* UDP listener */
326 stream = silc_net_udp_connect(params->bind_ip ? params->bind_ip :
327 params->local_ip, params->local_port,
328 NULL, 0, schedule);
329 listener->udp_listener =
330 silc_packet_stream_create(client->internal->packet_engine,
331 schedule, stream);
332 if (!listener->udp_listener) {
333 client->internal->ops->say(
334 client, NULL, SILC_CLIENT_MESSAGE_ERROR,
335 "Cannot create UDP listener on %s on port %d: %s",
336 params->bind_ip ? params->bind_ip :
337 params->local_ip, params->local_port, strerror(errno));
338 silc_client_listener_free(listener);
339 if (stream)
340 silc_stream_destroy(stream);
341 return NULL;
342 }
343 silc_packet_stream_link(listener->udp_listener,
344 &silc_client_listener_stream_cb, listener,
345 1000000, SILC_PACKET_ANY, -1);
346
347 if (!params->local_port) {
348 /* Get listener port */
349 SilcSocket sock;
350 silc_socket_stream_get_info(stream, &sock, NULL, NULL, NULL);
351 listener->params.local_port = silc_net_get_local_port(sock);
352 }
353 } else {
354 /* TCP listener */
355 listener->tcp_listener =
356 silc_net_tcp_create_listener(params->bind_ip ?
357 (const char **)¶ms->bind_ip :
358 (const char **)¶ms->local_ip,
359 1, params->local_port, TRUE, FALSE,
360 schedule, silc_client_listener_tcp_accept,
361 listener);
362 if (!listener->tcp_listener) {
363 client->internal->ops->say(
364 client, NULL, SILC_CLIENT_MESSAGE_ERROR,
365 "Cannot create listener on %s on port %d: %s",
366 params->bind_ip ? params->bind_ip :
367 params->local_ip, params->local_port, strerror(errno));
368
369 silc_client_listener_free(listener);
370 return NULL;
371 }
372
373 if (!params->local_port) {
374 /* Get listener port */
375 SilcUInt16 *ports;
376 ports = silc_net_listener_get_port(listener->tcp_listener, NULL);
377 listener->params.local_port = ports[0];
378 silc_free(ports);
379 }
380 }
381
382 SILC_LOG_DEBUG(("Bound listener to %s:%d",
383 params->bind_ip ? params->bind_ip : params->local_ip,
384 listener->params.local_port));
385
386 return listener;
387 }
388
389 /* Close and free listner */
390
silc_client_listener_free(SilcClientListener listener)391 void silc_client_listener_free(SilcClientListener listener)
392 {
393 if (listener->tcp_listener)
394 silc_net_close_listener(listener->tcp_listener);
395 silc_packet_stream_destroy(listener->udp_listener);
396 silc_free(listener);
397 }
398
399 /* Return listner bound port */
400
silc_client_listener_get_local_port(SilcClientListener listener)401 SilcUInt16 silc_client_listener_get_local_port(SilcClientListener listener)
402 {
403 return listener->params.local_port;
404 }
405