Statistics
| Branch: | Tag: | Revision:

root / src / charon / sa / tasks / ike_config.c @ 1427c93fcdab3eb3bfb83a657cd834c547339361

History | View | Annotate | Download (10 KB)

1
/*
2
 * Copyright (C) 2007 Martin Willi
3
 * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
4
 * Hochschule fuer Technik Rapperswil
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License as published by the
8
 * Free Software Foundation; either version 2 of the License, or (at your
9
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
10
 *
11
 * This program is distributed in the hope that it will be useful, but
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
 * for more details.
15
 */
16
17
#include "ike_config.h"
18
19
#include <daemon.h>
20
#include <encoding/payloads/cp_payload.h>
21
22
typedef struct private_ike_config_t private_ike_config_t;
23
24
/**
25
 * Private members of a ike_config_t task.
26
 */
27
struct private_ike_config_t {
28
29
    /**
30
     * Public methods and task_t interface.
31
     */
32
    ike_config_t public;
33
34
    /**
35
     * Assigned IKE_SA.
36
     */
37
    ike_sa_t *ike_sa;
38
39
    /**
40
     * Are we the initiator?
41
     */
42
    bool initiator;
43
44
    /**
45
     * virtual ip
46
     */
47
    host_t *virtual_ip;
48
49
    /**
50
     * list of attributes requested and its handler, entry_t
51
     */
52
    linked_list_t *requested;
53
};
54
55
/**
56
 * Entry for a requested attribute and the requesting handler
57
 */
58
typedef struct {
59
    /** attribute requested */
60
    configuration_attribute_type_t type;
61
    /** handler requesting this attribute */
62
    attribute_handler_t *handler;
63
} entry_t;
64
65
/**
66
 * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip
67
 */
68
static configuration_attribute_t *build_vip(host_t *vip)
69
{
70
    configuration_attribute_type_t type;
71
    chunk_t chunk, prefix;
72
73
    if (vip->get_family(vip) == AF_INET)
74
    {
75
        type = INTERNAL_IP4_ADDRESS;
76
        if (vip->is_anyaddr(vip))
77
        {
78
            chunk = chunk_empty;
79
        }
80
        else
81
        {
82
            chunk = vip->get_address(vip);
83
        }
84
    }
85
    else
86
    {
87
        type = INTERNAL_IP6_ADDRESS;
88
        if (vip->is_anyaddr(vip))
89
        {
90
            chunk = chunk_empty;
91
        }
92
        else
93
        {
94
            prefix = chunk_alloca(1);
95
            *prefix.ptr = 64;
96
            chunk = vip->get_address(vip);
97
            chunk = chunk_cata("cc", chunk, prefix);
98
        }
99
    }
100
    return configuration_attribute_create_value(type, chunk);
101
}
102
103
/**
104
 * Handle a received attribute as initiator
105
 */
106
static void handle_attribute(private_ike_config_t *this,
107
                             configuration_attribute_t *ca)
108
{
109
    attribute_handler_t *handler = NULL;
110
    enumerator_t *enumerator;
111
    entry_t *entry;
112
113
    /* find the handler which requested this attribute */
114
    enumerator = this->requested->create_enumerator(this->requested);
115
    while (enumerator->enumerate(enumerator, &entry))
116
    {
117
        if (entry->type == ca->get_type(ca))
118
        {
119
            handler = entry->handler;
120
            this->requested->remove_at(this->requested, enumerator);
121
            free(entry);
122
            break;
123
        }
124
    }
125
    enumerator->destroy(enumerator);
126
127
    /* and pass it to the handle function */
128
    handler = lib->attributes->handle(lib->attributes,
129
                            this->ike_sa->get_other_id(this->ike_sa), handler,
130
                            ca->get_type(ca), ca->get_value(ca));
131
    if (handler)
132
    {
133
        this->ike_sa->add_configuration_attribute(this->ike_sa,
134
                handler, ca->get_type(ca), ca->get_value(ca));
135
    }
136
}
137
138
/**
139
 * process a single configuration attribute
140
 */
141
static void process_attribute(private_ike_config_t *this,
142
                              configuration_attribute_t *ca)
143
{
144
    host_t *ip;
145
    chunk_t addr;
146
    int family = AF_INET6;
147
148
    switch (ca->get_type(ca))
149
    {
150
        case INTERNAL_IP4_ADDRESS:
151
            family = AF_INET;
152
            /* fall */
153
        case INTERNAL_IP6_ADDRESS:
154
        {
155
            addr = ca->get_value(ca);
156
            if (addr.len == 0)
157
            {
158
                ip = host_create_any(family);
159
            }
160
            else
161
            {
162
                /* skip prefix byte in IPv6 payload*/
163
                if (family == AF_INET6)
164
                {
165
                    addr.len--;
166
                }
167
                ip = host_create_from_chunk(family, addr, 0);
168
            }
169
            if (ip)
170
            {
171
                DESTROY_IF(this->virtual_ip);
172
                this->virtual_ip = ip;
173
            }
174
            break;
175
        }
176
        default:
177
        {
178
            if (this->initiator)
179
            {
180
                handle_attribute(this, ca);
181
            }
182
        }
183
    }
184
}
185
186
/**
187
 * Scan for configuration payloads and attributes
188
 */
189
static void process_payloads(private_ike_config_t *this, message_t *message)
190
{
191
    enumerator_t *enumerator, *attributes;
192
    payload_t *payload;
193
194
    enumerator = message->create_payload_enumerator(message);
195
    while (enumerator->enumerate(enumerator, &payload))
196
    {
197
        if (payload->get_type(payload) == CONFIGURATION)
198
        {
199
            cp_payload_t *cp = (cp_payload_t*)payload;
200
            configuration_attribute_t *ca;
201
202
            switch (cp->get_type(cp))
203
            {
204
                case CFG_REQUEST:
205
                case CFG_REPLY:
206
                {
207
                    attributes = cp->create_attribute_enumerator(cp);
208
                    while (attributes->enumerate(attributes, &ca))
209
                    {
210
                        process_attribute(this, ca);
211
                    }
212
                    attributes->destroy(attributes);
213
                    break;
214
                }
215
                default:
216
                    DBG1(DBG_IKE, "ignoring %N config payload",
217
                         config_type_names, cp->get_type(cp));
218
                    break;
219
            }
220
        }
221
    }
222
    enumerator->destroy(enumerator);
223
}
224
225
/**
226
 * Implementation of task_t.process for initiator
227
 */
228
static status_t build_i(private_ike_config_t *this, message_t *message)
229
{
230
    if (message->get_message_id(message) == 1)
231
    {    /* in first IKE_AUTH only */
232
        cp_payload_t *cp = NULL;
233
        enumerator_t *enumerator;
234
        attribute_handler_t *handler;
235
        peer_cfg_t *config;
236
        configuration_attribute_type_t type;
237
        chunk_t data;
238
        host_t *vip;
239
240
        /* reuse virtual IP if we already have one */
241
        vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
242
        if (!vip)
243
        {
244
            config = this->ike_sa->get_peer_cfg(this->ike_sa);
245
            vip = config->get_virtual_ip(config);
246
        }
247
        if (vip)
248
        {
249
            cp = cp_payload_create_type(CFG_REQUEST);
250
            cp->add_attribute(cp, build_vip(vip));
251
        }
252
253
        enumerator = lib->attributes->create_initiator_enumerator(lib->attributes,
254
                                this->ike_sa->get_other_id(this->ike_sa), vip);
255
        while (enumerator->enumerate(enumerator, &handler, &type, &data))
256
        {
257
            configuration_attribute_t *ca;
258
            entry_t *entry;
259
260
            /* create configuration attribute */
261
            ca = configuration_attribute_create_value(type, data);
262
            if (!cp)
263
            {
264
                cp = cp_payload_create_type(CFG_REQUEST);
265
            }
266
            cp->add_attribute(cp, ca);
267
268
            /* save handler along with requested type */
269
            entry = malloc_thing(entry_t);
270
            entry->type = type;
271
            entry->handler = handler;
272
273
            this->requested->insert_last(this->requested, entry);
274
        }
275
        enumerator->destroy(enumerator);
276
277
        if (cp)
278
        {
279
            message->add_payload(message, (payload_t*)cp);
280
        }
281
    }
282
    return NEED_MORE;
283
}
284
285
/**
286
 * Implementation of task_t.process for responder
287
 */
288
static status_t process_r(private_ike_config_t *this, message_t *message)
289
{
290
    if (message->get_message_id(message) == 1)
291
    {    /* in first IKE_AUTH only */
292
        process_payloads(this, message);
293
    }
294
    return NEED_MORE;
295
}
296
297
/**
298
 * Implementation of task_t.build for responder
299
 */
300
static status_t build_r(private_ike_config_t *this, message_t *message)
301
{
302
    if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
303
    {    /* in last IKE_AUTH exchange */
304
        enumerator_t *enumerator;
305
        configuration_attribute_type_t type;
306
        chunk_t value;
307
        host_t *vip = NULL;
308
        cp_payload_t *cp = NULL;
309
        peer_cfg_t *config;
310
311
        config = this->ike_sa->get_peer_cfg(this->ike_sa);
312
        if (config && this->virtual_ip)
313
        {
314
            DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
315
            if (config->get_pool(config))
316
            {
317
                vip = lib->attributes->acquire_address(lib->attributes,
318
                                    config->get_pool(config),
319
                                    this->ike_sa->get_other_id(this->ike_sa),
320
                                    this->virtual_ip);
321
            }
322
            if (vip == NULL)
323
            {
324
                DBG1(DBG_IKE, "no virtual IP found, sending %N",
325
                     notify_type_names, INTERNAL_ADDRESS_FAILURE);
326
                message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE,
327
                                    chunk_empty);
328
                return SUCCESS;
329
            }
330
            DBG1(DBG_IKE, "assigning virtual IP %H to peer", vip);
331
            this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip);
332
333
            cp = cp_payload_create_type(CFG_REPLY);
334
            cp->add_attribute(cp, build_vip(vip));
335
        }
336
337
        /* query registered providers for additional attributes to include */
338
        enumerator = lib->attributes->create_responder_enumerator(
339
                lib->attributes, this->ike_sa->get_other_id(this->ike_sa), vip);
340
        while (enumerator->enumerate(enumerator, &type, &value))
341
        {
342
            if (!cp)
343
            {
344
                cp = cp_payload_create_type(CFG_REPLY);
345
            }
346
            cp->add_attribute(cp,
347
                        configuration_attribute_create_value(type, value));
348
        }
349
        enumerator->destroy(enumerator);
350
351
        if (cp)
352
        {
353
            message->add_payload(message, (payload_t*)cp);
354
        }
355
        DESTROY_IF(vip);
356
        return SUCCESS;
357
    }
358
    return NEED_MORE;
359
}
360
361
/**
362
 * Implementation of task_t.process for initiator
363
 */
364
static status_t process_i(private_ike_config_t *this, message_t *message)
365
{
366
    if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
367
    {    /* in last IKE_AUTH exchange */
368
369
        process_payloads(this, message);
370
371
        if (this->virtual_ip)
372
        {
373
            this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
374
        }
375
        return SUCCESS;
376
    }
377
    return NEED_MORE;
378
}
379
380
/**
381
 * Implementation of task_t.get_type
382
 */
383
static task_type_t get_type(private_ike_config_t *this)
384
{
385
    return IKE_CONFIG;
386
}
387
388
/**
389
 * Implementation of task_t.migrate
390
 */
391
static void migrate(private_ike_config_t *this, ike_sa_t *ike_sa)
392
{
393
    DESTROY_IF(this->virtual_ip);
394
395
    this->ike_sa = ike_sa;
396
    this->virtual_ip = NULL;
397
    this->requested->destroy_function(this->requested, free);
398
    this->requested = linked_list_create();
399
}
400
401
/**
402
 * Implementation of task_t.destroy
403
 */
404
static void destroy(private_ike_config_t *this)
405
{
406
    DESTROY_IF(this->virtual_ip);
407
    this->requested->destroy_function(this->requested, free);
408
    free(this);
409
}
410
411
/*
412
 * Described in header.
413
 */
414
ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator)
415
{
416
    private_ike_config_t *this = malloc_thing(private_ike_config_t);
417
418
    this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
419
    this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
420
    this->public.task.destroy = (void(*)(task_t*))destroy;
421
422
    this->initiator = initiator;
423
    this->ike_sa = ike_sa;
424
    this->virtual_ip = NULL;
425
    this->requested = linked_list_create();
426
427
    if (initiator)
428
    {
429
        this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
430
        this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
431
    }
432
    else
433
    {
434
        this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
435
        this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
436
    }
437
438
    return &this->public;
439
}
440