support of ModeCfg Push mode
[strongswan.git] / src / pluto / modecfg.c
1 /* Mode config related functions
2 * Copyright (C) 2001-2002 Colubris Networks
3 * Copyright (C) 2003 Sean Mathews - Nu Tech Software Solutions, inc.
4 * Copyright (C) 2003-2004 Xelerance Corporation
5 * Copyright (C) 2006 Andreas Steffen - Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 *
17 * RCSID $Id: modecfg.c,v 1.6 2006/04/24 20:44:57 as Exp $
18 *
19 * This code originally written by Colubris Networks, Inc.
20 * Extraction of patch and porting to 1.99 codebases by Xelerance Corporation
21 * Porting to 2.x by Sean Mathews
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <freeswan.h>
29
30 #include "constants.h"
31 #include "defs.h"
32 #include "state.h"
33 #include "demux.h"
34 #include "timer.h"
35 #include "ipsec_doi.h"
36 #include "log.h"
37 #include "md5.h"
38 #include "sha1.h"
39 #include "crypto.h"
40 #include "modecfg.h"
41 #include "whack.h"
42
43 #define SUPPORTED_ATTR_SET ( LELEM(INTERNAL_IP4_ADDRESS) \
44 | LELEM(INTERNAL_IP4_NETMASK) \
45 | LELEM(INTERNAL_IP4_DNS) \
46 | LELEM(INTERNAL_IP4_NBNS) \
47 )
48
49 /*
50 * Addresses assigned (usually via ModeCfg) to the Initiator
51 */
52 typedef struct internal_addr internal_addr_t;
53
54 struct internal_addr
55 {
56 lset_t attr_set;
57 ip_address ipaddr;
58 ip_address dns[2];
59 ip_address wins[2];
60 };
61
62 /*
63 * Initialize an internal_addr struct
64 */
65 static void
66 init_internal_addr(internal_addr_t *ia)
67 {
68 ia->attr_set = LEMPTY;
69 anyaddr(AF_INET, &ia->ipaddr);
70 anyaddr(AF_INET, &ia->dns[0]);
71 anyaddr(AF_INET, &ia->dns[1]);
72 anyaddr(AF_INET, &ia->wins[0]);
73 anyaddr(AF_INET, &ia->wins[1]);
74 }
75
76 /*
77 * get internal IP address for a connection
78 */
79 static void
80 get_internal_addr(struct connection *c, internal_addr_t *ia)
81 {
82 init_internal_addr(ia);
83
84 if (isanyaddr(&c->spd.that.host_srcip))
85 {
86 /* not defined in connection - fetch it from LDAP */
87 }
88 else
89 {
90 char srcip[ADDRTOT_BUF];
91
92 ia->ipaddr = c->spd.that.host_srcip;
93
94 addrtot(&ia->ipaddr, 0, srcip, sizeof(srcip));
95 plog("assigning virtual IP source address %s", srcip);
96 }
97
98 if (!isanyaddr(&ia->ipaddr)) /* We got an IP address, send it */
99 {
100 c->spd.that.client.addr = ia->ipaddr;
101 c->spd.that.client.maskbits = 32;
102 c->spd.that.has_client = TRUE;
103
104 ia->attr_set |= LELEM(INTERNAL_IP4_ADDRESS) | LELEM(INTERNAL_IP4_NETMASK);
105 }
106
107
108 if (!isanyaddr(&ia->dns[0])) /* We got DNS addresses, send them */
109 ia->attr_set |= LELEM(INTERNAL_IP4_DNS);
110
111 if (!isanyaddr(&ia->wins[0])) /* We got WINS addresses, send them */
112 ia->attr_set |= LELEM(INTERNAL_IP4_NBNS);
113 }
114
115 /*
116 * Set srcip and client subnet to internal IP address
117 */
118 static bool
119 set_internal_addr(struct connection *c, internal_addr_t *ia)
120 {
121 if (ia->attr_set & LELEM(INTERNAL_IP4_ADDRESS)
122 && !isanyaddr(&ia->ipaddr))
123 {
124 if (addrbytesptr(&c->spd.this.host_srcip, NULL) == 0
125 || isanyaddr(&c->spd.this.host_srcip)
126 || sameaddr(&c->spd.this.host_srcip, &ia->ipaddr))
127 {
128 char srcip[ADDRTOT_BUF];
129
130 addrtot(&ia->ipaddr, 0, srcip, sizeof(srcip));
131 plog("setting virtual IP source address to %s", srcip);
132 }
133 else
134 {
135 char old_srcip[ADDRTOT_BUF];
136 char new_srcip[ADDRTOT_BUF];
137
138 addrtot(&c->spd.this.host_srcip, 0, old_srcip, sizeof(old_srcip));
139 addrtot(&ia->ipaddr, 0, new_srcip, sizeof(new_srcip));
140 plog("replacing virtual IP source address %s by %s"
141 , old_srcip, new_srcip);
142 }
143
144 /* setting srcip */
145 c->spd.this.host_srcip = ia->ipaddr;
146
147 /* setting client subnet to srcip/32 */
148 addrtosubnet(&ia->ipaddr, &c->spd.this.client);
149 setportof(0, &c->spd.this.client.addr);
150 c->spd.this.has_client = TRUE;
151 return TRUE;
152 }
153 return FALSE;
154 }
155
156 /*
157 * Compute HASH of Mode Config.
158 */
159 static size_t
160 modecfg_hash(u_char *dest, const u_char *start, const u_char *roof
161 , const struct state *st)
162 {
163 struct hmac_ctx ctx;
164
165 hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a);
166 hmac_update(&ctx, (const u_char *) &st->st_msgid, sizeof(st->st_msgid));
167 hmac_update(&ctx, start, roof-start);
168 hmac_final(dest, &ctx);
169
170 DBG(DBG_CRYPT,
171 DBG_log("ModeCfg HASH computed:");
172 DBG_dump("", dest, ctx.hmac_digest_size)
173 )
174 return ctx.hmac_digest_size;
175 }
176
177
178 /*
179 * Generate an IKE message containing ModeCfg information (eg: IP, DNS, WINS)
180 */
181 static stf_status
182 modecfg_build_msg(struct state *st, pb_stream *rbody
183 , u_int16_t msg_type
184 , internal_addr_t *ia
185 , u_int16_t ap_id)
186 {
187 u_char *r_hash_start, *r_hashval;
188
189 START_HASH_PAYLOAD(*rbody, ISAKMP_NEXT_ATTR);
190
191 /* ATTR out */
192 {
193 struct isakmp_mode_attr attrh;
194 struct isakmp_attribute attr;
195 pb_stream strattr,attrval;
196 int attr_type;
197 int dns_idx, wins_idx;
198 bool dont_advance;
199 lset_t attr_set = ia->attr_set;
200
201 attrh.isama_np = ISAKMP_NEXT_NONE;
202 attrh.isama_type = msg_type;
203 attrh.isama_identifier = ap_id;
204
205 if (!out_struct(&attrh, &isakmp_attr_desc, rbody, &strattr))
206 return STF_INTERNAL_ERROR;
207
208 attr_type = 0;
209 dns_idx = 0;
210 wins_idx = 0;
211
212 while (attr_set != 0)
213 {
214 dont_advance = FALSE;
215 if (attr_set & 1)
216 {
217 const u_char *byte_ptr;
218 u_int len;
219
220 /* ISAKMP attr out */
221 attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TLV;
222 out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval);
223
224 switch (attr_type)
225 {
226 case INTERNAL_IP4_ADDRESS:
227 if (!isanyaddr(&ia->ipaddr))
228 {
229 len = addrbytesptr(&ia->ipaddr, &byte_ptr);
230 out_raw(byte_ptr, len, &attrval, "IP4_addr");
231 }
232 break;
233 case INTERNAL_IP4_NETMASK:
234 {
235 u_int mask;
236 #if 0
237 char mask[4],bits[8]={0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe};
238 int t,m=st->st_connection->that.host_addr.maskbit;
239 for (t=0; t<4; t++)
240 {
241 if (m < 8)
242 mask[t] = bits[m];
243 else
244 mask[t] = 0xff;
245 m -= 8;
246 }
247 #endif
248 if (st->st_connection->spd.this.client.maskbits == 0)
249 mask = 0;
250 else
251 mask = 0xffffffff * 1;
252 out_raw(&mask, 4, &attrval, "IP4_mask");
253 }
254 break;
255 case INTERNAL_IP4_SUBNET:
256 {
257 char mask[4];
258 char bits[8] = {0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe};
259 int t;
260 int m = st->st_connection->spd.this.client.maskbits;
261
262 for (t = 0; t < 4; t++)
263 {
264 if (m < 8)
265 mask[t] = bits[m];
266 else
267 mask[t] = 0xff;
268 m -= 8;
269 if (m < 0)
270 m = 0;
271 }
272 len = addrbytesptr(&st->st_connection->spd.this.client.addr, &byte_ptr);
273 out_raw(byte_ptr, len, &attrval, "IP4_subnet");
274 out_raw(mask, sizeof(mask), &attrval, "IP4_submsk");
275 }
276 break;
277 case INTERNAL_IP4_DNS:
278 if (!isanyaddr(&ia->dns[dns_idx]))
279 {
280 len = addrbytesptr(&ia->dns[dns_idx++], &byte_ptr);
281 out_raw(byte_ptr, len, &attrval, "IP4_dns");
282 }
283 if (dns_idx < 2 && !isanyaddr(&ia->dns[dns_idx]))
284 {
285 dont_advance = TRUE;
286 }
287 break;
288 case INTERNAL_IP4_NBNS:
289 if (!isanyaddr(&ia->wins[wins_idx]))
290 {
291 len = addrbytesptr(&ia->wins[wins_idx++], &byte_ptr);
292 out_raw(byte_ptr, len, &attrval, "IP4_wins");
293 }
294 if (wins_idx < 2 && !isanyaddr(&ia->wins[wins_idx]))
295 {
296 dont_advance = TRUE;
297 }
298 break;
299 default:
300 plog("attempt to send unsupported mode cfg attribute %s."
301 , enum_show(&modecfg_attr_names, attr_type));
302 break;
303 }
304 close_output_pbs(&attrval);
305 }
306 if (!dont_advance)
307 {
308 attr_type++;
309 attr_set >>= 1;
310 }
311 }
312 close_message(&strattr);
313 }
314
315 modecfg_hash(r_hashval, r_hash_start, rbody->cur,st);
316 close_message(rbody);
317 encrypt_message(rbody, st);
318 return STF_OK;
319 }
320
321 /*
322 * Send ModeCfg message
323 */
324 static stf_status
325 modecfg_send_msg(struct state *st, int isama_type, internal_addr_t *ia)
326 {
327 pb_stream msg;
328 pb_stream rbody;
329 char buf[BUF_LEN];
330
331 /* set up attr */
332 init_pbs(&msg, buf, sizeof(buf), "ModeCfg msg buffer");
333
334 /* this is the beginning of a new exchange */
335 st->st_msgid = generate_msgid(st);
336 init_phase2_iv(st, &st->st_msgid);
337
338 /* HDR out */
339 {
340 struct isakmp_hdr hdr;
341
342 zero(&hdr); /* default to 0 */
343 hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
344 hdr.isa_np = ISAKMP_NEXT_HASH;
345 hdr.isa_xchg = ISAKMP_XCHG_MODE_CFG;
346 hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
347 memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
348 memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
349 hdr.isa_msgid = st->st_msgid;
350
351 if (!out_struct(&hdr, &isakmp_hdr_desc, &msg, &rbody))
352 {
353 return STF_INTERNAL_ERROR;
354 }
355 }
356
357 /* ATTR out */
358 modecfg_build_msg(st, &rbody
359 , isama_type
360 , ia
361 , 0 /* XXX isama_id */
362 );
363
364 clonetochunk(st->st_tpacket, msg.start, pbs_offset(&msg), "ModeCfg msg");
365
366 /* Transmit */
367 send_packet(st, "ModeCfg msg");
368
369 if (st->st_event->ev_type != EVENT_RETRANSMIT)
370 {
371 delete_event(st);
372 event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
373 }
374 st->st_modecfg.started = TRUE;
375 return STF_OK;
376 }
377
378 /*
379 * Send ModeCfg request message from client to server in pull mode
380 */
381 stf_status
382 modecfg_send_request(struct state *st)
383 {
384 internal_addr_t ia;
385
386 init_internal_addr(&ia);
387 ia.attr_set = LELEM(INTERNAL_IP4_ADDRESS)
388 | LELEM(INTERNAL_IP4_NETMASK);
389
390 plog("sending ModeCfg request");
391 st->st_state = STATE_MODE_CFG_I1;
392 return modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia);
393 }
394
395 /*
396 * Send ModeCfg set message from server to client in push mode
397 */
398 stf_status
399 modecfg_send_set(struct state *st)
400 {
401 internal_addr_t ia;
402
403 get_internal_addr(st->st_connection, &ia);
404
405 plog("sending ModeCfg set");
406 st->st_state = STATE_MODE_CFG_R1;
407 return modecfg_send_msg(st, ISAKMP_CFG_SET, &ia);
408 }
409
410 /*
411 * Parse a ModeCfg attribute payload
412 */
413 static stf_status
414 modecfg_parse_attributes(pb_stream *attrs, internal_addr_t *ia)
415 {
416 struct isakmp_attribute attr;
417 pb_stream strattr;
418
419 while (pbs_left(attrs) >= sizeof(struct isakmp_attribute))
420 {
421 u_int16_t attr_type;
422 u_int16_t attr_len;
423
424 if (!in_struct(&attr, &isakmp_modecfg_attribute_desc, attrs, &strattr))
425 {
426 return STF_FAIL;
427 }
428 attr_type = attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK;
429 attr_len = attr.isaat_lv;
430
431 switch (attr_type)
432 {
433 case INTERNAL_IP4_ADDRESS:
434 if (attr_len == 4)
435 {
436 initaddr((char *)(strattr.cur), 4, AF_INET, &ia->ipaddr);
437 }
438 /* fall through to set attribute flags */
439 case INTERNAL_IP4_NETMASK:
440 case INTERNAL_IP4_DNS:
441 case INTERNAL_IP4_SUBNET:
442 case INTERNAL_IP4_NBNS:
443 ia->attr_set |= LELEM(attr_type);
444 break;
445 default:
446 plog("unsupported ModeCfg attribute %s received."
447 , enum_show(&modecfg_attr_names, attr_type));
448 break;
449 }
450 }
451 return STF_OK;
452 }
453
454 /*
455 * Parse a ModeCfg message
456 */
457 static stf_status
458 modecfg_parse_msg(struct msg_digest *md, int isama_type, u_int16_t *isama_id
459 , internal_addr_t *ia)
460 {
461 struct state *const st = md->st;
462 struct payload_digest *p;
463 stf_status stat;
464
465 st->st_msgid = md->hdr.isa_msgid;
466
467 CHECK_QUICK_HASH(md, modecfg_hash(hash_val
468 , hash_pbs->roof
469 , md->message_pbs.roof, st)
470 , "MODECFG-HASH", "ISAKMP_CFG_MSG");
471
472 /* process the ModeCfg payloads received */
473 for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next)
474 {
475 internal_addr_t ia_candidate;
476
477 init_internal_addr(&ia_candidate);
478
479 if (p->payload.attribute.isama_type == isama_type)
480 {
481 *isama_id = p->payload.attribute.isama_identifier;
482
483 stat = modecfg_parse_attributes(&p->pbs, &ia_candidate);
484 if (stat == STF_OK)
485 {
486 /* retrun with a valid set of attributes */
487 *ia = ia_candidate;
488 return STF_OK;
489 }
490 }
491 else
492 {
493 plog("expected %s, got %s instead (ignored)"
494 , enum_name(&attr_msg_type_names, isama_type)
495 , enum_name(&attr_msg_type_names, p->payload.attribute.isama_type));
496
497 stat = modecfg_parse_attributes(&p->pbs, &ia_candidate);
498 }
499 if (stat != STF_OK)
500 return stat;
501 }
502 return STF_IGNORE;
503 }
504
505 /* STATE_MODE_CFG_R0:
506 * HDR*, HASH, ATTR(REQ=IP) --> HDR*, HASH, ATTR(REPLY=IP)
507 *
508 * used in ModeCfg pull mode, on the server (responder)
509 */
510 stf_status
511 modecfg_inR0(struct msg_digest *md)
512 {
513 struct state *const st = md->st;
514 u_int16_t isama_id;
515 internal_addr_t ia;
516 stf_status stat;
517
518 stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia);
519 if (stat != STF_OK)
520 return stat;
521
522 get_internal_addr(st->st_connection, &ia);
523
524 /* build ISAKMP_CFG_REPLY */
525 stat = modecfg_build_msg(st, &md->rbody
526 , ISAKMP_CFG_REPLY
527 , &ia
528 , isama_id);
529 if (stat != STF_OK)
530 {
531 /* notification payload - not exactly the right choice, but okay */
532 md->note = ATTRIBUTES_NOT_SUPPORTED;
533 return stat;
534 }
535
536 st->st_msgid = 0;
537 return STF_OK;
538 }
539
540 /* STATE_MODE_CFG_R1:
541 * HDR*, HASH, ATTR(ACK,OK)
542 *
543 * used in ModeCfg push mode, on the server (responder)
544 */
545 stf_status
546 modecfg_inR1(struct msg_digest *md)
547 {
548 struct state *const st = md->st;
549 u_int16_t isama_id;
550 internal_addr_t ia;
551 stf_status stat;
552
553 plog("parsing ModeCfg ack");
554
555 stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia);
556 if (stat != STF_OK)
557 return stat;
558
559 st->st_msgid = 0;
560 return STF_OK;
561 }
562
563 /* STATE_MODE_CFG_I1:
564 * HDR*, HASH, ATTR(REPLY=IP)
565 *
566 * used in ModeCfg pull mode, on the client (initiator)
567 */
568 stf_status
569 modecfg_inI1(struct msg_digest *md)
570 {
571 struct state *const st = md->st;
572 u_int16_t isama_id;
573 internal_addr_t ia;
574 stf_status stat;
575
576 plog("parsing ModeCfg reply");
577
578 stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia);
579 if (stat != STF_OK)
580 return stat;
581
582 st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia);
583 st->st_msgid = 0;
584 return STF_OK;
585 }
586
587 /* STATE_MODE_CFG_I2:
588 * HDR*, HASH, ATTR(SET=IP) --> HDR*, HASH, ATTR(ACK,OK)
589 *
590 * used in ModeCfg push mode, on the client (initiator).
591 */
592 stf_status
593 modecfg_inI2(struct msg_digest *md)
594 {
595 struct state *const st = md->st;
596 u_int16_t isama_id;
597 internal_addr_t ia;
598 lset_t attr_set;
599 stf_status stat;
600
601 plog("parsing ModeCfg set");
602
603 stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia);
604 if (stat != STF_OK)
605 return stat;
606
607 st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia);
608
609 /* prepare ModeCfg ack which sends zero length attributes */
610 attr_set = ia.attr_set;
611 init_internal_addr(&ia);
612 ia.attr_set = attr_set & SUPPORTED_ATTR_SET;
613
614 stat = modecfg_build_msg(st, &md->rbody
615 , ISAKMP_CFG_ACK
616 , &ia
617 , isama_id);
618 if (stat != STF_OK)
619 {
620 /* notification payload - not exactly the right choice, but okay */
621 md->note = ATTRIBUTES_NOT_SUPPORTED;
622 return stat;
623 }
624
625 st->st_msgid = 0;
626 return STF_OK;
627 }