aboutsummaryrefslogtreecommitdiffstats
path: root/src/pluto/connections.h
blob: ee2e00da618f61daaf9145395655c961841dabbc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
/* information about connections between hosts and clients
 * Copyright (C) 1998-2001  D. Hugh Redelmeier
 * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

#ifndef _CONNECTIONS_H
#define _CONNECTIONS_H

#include <sys/queue.h>

#include <utils/linked_list.h>
#include <utils/identification.h>
#include <credentials/ietf_attributes/ietf_attributes.h>

#include "certs.h"
#include "smartcard.h"
#include "whack.h"

/* There are two kinds of connections:
 * - ISAKMP connections, between hosts (for IKE communication)
 * - IPsec connections, between clients (for secure IP communication)
 *
 * An ISAKMP connection looks like:
 *   host<--->host
 *
 * An IPsec connection looks like:
 *   client-subnet<-->host<->nexthop<--->nexthop<->host<-->client-subnet
 *
 * For the connection to be relevant to this instance of Pluto,
 * exactly one of the hosts must be a public interface of our machine
 * known to this instance.
 *
 * The client subnet might simply be the host -- this is a
 * representation of "host mode".
 *
 * Each nexthop defaults to the neighbouring host's IP address.
 * The nexthop is a property of the pair of hosts, not each
 * individually.  It is only needed for IPsec because of the
 * way IPsec is mixed into the kernel routing logic.  Furthermore,
 * only this end's nexthop is actually used.  Eventually, nexthop
 * will be unnecessary.
 *
 * Other information represented:
 * - each connection has a name: a chunk of uninterpreted text
 *   that is unique for each connection.
 * - security requirements (currently just the "policy" flags from
 *   the whack command to initiate the connection, but eventually
 *   much more.  Different for ISAKMP and IPsec connections.
 * - rekeying parameters:
 *   + time an SA may live
 *   + time before SA death that a rekeying should be attempted
 *     (only by the initiator)
 *   + number of times to attempt rekeying
 * - With the current KLIPS, we must route packets for a client
 *   subnet through the ipsec interface (ipsec0).  Only one
 *   gateway can get traffic for a specific (client) subnet.
 *   Furthermore, if the routing isn't in place, packets will
 *   be sent in the clear.
 *   "routing" indicates whether the routing has been done for
 *   this connection.  Note that several connections may claim
 *   the same routing, as long as they agree about where the
 *   packets are to be sent.
 * - With the current KLIPS, only one outbound IPsec SA bundle can be
 *   used for a particular client.  This is due to a limitation
 *   of using only routing for selection.  So only one IPsec state (SA)
 *   may "own" the eroute.  "eroute_owner" is the serial number of
 *   this state, SOS_NOBODY if there is none.  "routing" indicates
 *   what kind of erouting has been done for this connection, if any.
 *
 * Details on routing is in constants.h
 *
 * Operations on Connections:
 *
 * - add a new connection (with all details) [whack command]
 * - delete a connection (by name) [whack command]
 * - initiate a connection (by name) [whack command]
 * - find a connection (by IP addresses of hosts)
 *   [response to peer request; finding ISAKMP connection for IPsec connection]
 *
 * Some connections are templates, missing the address of the peer
 * (represented by INADDR_ANY).  These are always arranged so that the
 * missing end is "that" (there can only be one missing end).  These can
 * be instantiated (turned into real connections) by Pluto in one of two
 * different ways: Road Warrior Instantiation or Opportunistic
 * Instantiation.  A template connection is marked for Opportunistic
 * Instantiation by specifying the peer client as 0.0.0.0/32 (or the IPV6
 * equivalent).  Otherwise, it is suitable for Road Warrior Instantiation.
 *
 * Instantiation creates a new temporary connection, with the missing
 * details filled in.  The resulting template lasts only as long as there
 * is a state that uses it.
 */

/* connection policy priority: how important this policy is
 * - used to implement eroute-like precedence (augmented by a small
 *   bonus for a routed connection).
 * - a whole number
 * - larger is more important
 * - three subcomponents.  In order of decreasing significance:
 *   + length of source subnet mask (8 bits)
 *   + length of destination subnet mask (8 bits)
 *   + bias (8 bit)
 * - a bias of 1 is added to allow prio BOTTOM_PRIO to be less than all
 *   normal priorities
 * - other bias values are created on the fly to give mild preference
 *   to certaion conditions (eg. routedness)
 * - priority is inherited -- an instance of a policy has the same priority
 *   as the original policy, even though its subnets might be smaller.
 * - display format: n,m
 */
typedef unsigned long policy_prio_t;
#define BOTTOM_PRIO   ((policy_prio_t)0)        /* smaller than any real prio */
#define set_policy_prio(c) { (c)->prio = \
		((policy_prio_t)(c)->spd.this.client.maskbits << 16) \
		| ((policy_prio_t)(c)->spd.that.client.maskbits << 8) \
		| (policy_prio_t)1; }
#define POLICY_PRIO_BUF (3+1+3+1)
extern void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]);

struct virtual_t;

struct end {
	identification_t *id;
	ip_address
		host_addr,
		host_nexthop,
		host_srcip;
	ip_subnet client;

	bool key_from_DNS_on_demand;
	bool has_client;
	bool has_client_wildcard;
	bool has_port_wildcard;
	bool has_id_wildcards;
	bool has_natip;
	char *updown;
	u_int16_t host_port;        /* host order */
	u_int16_t port;             /* host order */
	u_int8_t protocol;
	cert_t *cert;               /* end certificate */
	identification_t *ca;       /* CA distinguished name */
	ietf_attributes_t *groups;  /* access control groups */
	smartcard_t *sc;            /* smartcard reader and key info */
	struct virtual_t *virt;
	bool modecfg;               /* this end: request local address from server */
								/* that end: give local addresses to clients */
	char *pool;					/* name of an associated virtual IP address pool */
	bool hostaccess;            /* allow access to host via iptables INPUT/OUTPUT */
								/* rules if client behind host is a subnet */
	bool allow_any;             /* IP address is subject to change */
	certpolicy_t sendcert;      /* whether or not to send the certificate */
};

struct spd_route {
	struct spd_route *next;
	struct end this;
	struct end that;
	so_serial_t eroute_owner;
	enum routing_t routing;     /* level of routing in place */
	uint32_t reqid;
};

typedef struct connection connection_t;

struct connection {
	char *name;
	bool ikev1;

	lset_t policy;
	time_t sa_ike_life_seconds;
	time_t sa_ipsec_life_seconds;
	time_t sa_rekey_margin;
	unsigned long sa_rekey_fuzz;
	unsigned long sa_keying_tries;

	/* RFC 3706 DPD */
	time_t dpd_delay;
	time_t dpd_timeout;
	dpd_action_t dpd_action;

	char              *log_file_name;     /* name of log file */
	FILE              *log_file;          /* possibly open FILE */
	TAILQ_ENTRY(connection) log_link;     /* linked list of open conns */
	bool               log_file_err;      /* only bitch once */

	struct spd_route spd;

	/* internal fields: */

	unsigned long instance_serial;
	policy_prio_t prio;
	bool instance_initiation_ok;        /* this is an instance of a policy that mandates initiate */
	enum connection_kind kind;
	const struct iface *interface;      /* filled in iff oriented */

	so_serial_t /* state object serial number */
		newest_isakmp_sa,
		newest_ipsec_sa;


#ifdef DEBUG
	lset_t extra_debugging;
#endif

	/* note: if the client is the gateway, the following must be equal */
	sa_family_t addr_family;            /* between gateways */
	sa_family_t tunnel_addr_family;     /* between clients */

	connection_t *policy_next;          /* if multiple policies,
										   next one to apply */
	struct gw_info *gw_info;
	struct alg_info_esp *alg_info_esp;
	struct alg_info_ike *alg_info_ike;
	struct host_pair *host_pair;
	connection_t *hp_next;              /* host pair list link */
	connection_t *ac_next;              /* all connections list link */
	linked_list_t *requested_ca;        /* collected certificate requests */
	bool got_certrequest;
};

#define oriented(c) ((c).interface != NULL)
extern bool orient(connection_t *c);

extern bool same_peer_ids(const connection_t *c, const connection_t *d,
						  identification_t *his_id);

/* Format the topology of a connection end, leaving out defaults.
 * Largest left end looks like: client === host : port [ host_id ] --- hop
 * Note: if that==NULL, skip nexthop
 */
#define END_BUF (SUBNETTOT_BUF + ADDRTOT_BUF + IDTOA_BUF + ADDRTOT_BUF + 10)
extern size_t format_end(char *buf, size_t buf_len, const struct end *this,
						 const struct end *that, bool is_left, lset_t policy);

extern void add_connection(const whack_message_t *wm);
extern void initiate_connection(const char *name, int whackfd);
extern void initiate_opportunistic(const ip_address *our_client,
								   const ip_address *peer_client,
								   int transport_proto, bool held, int whackfd);
extern void terminate_connection(const char *nm);
extern void release_connection(connection_t *c, bool relations);
extern void delete_connection(connection_t *c, bool relations);
extern void delete_connections_by_name(const char *name, bool strict);
extern void delete_every_connection(void);
extern char *add_group_instance(connection_t *group, const ip_subnet *target);
extern void remove_group_instance(const connection_t *group, const char *name);
extern void release_dead_interfaces(void);
extern void check_orientations(void);
extern connection_t *route_owner(connection_t *c, struct spd_route **srp,
								 connection_t **erop, struct spd_route **esrp);
extern connection_t *shunt_owner(const ip_subnet *ours, const ip_subnet *his);

extern bool uniqueIDs;  /* --uniqueids? */
extern void ISAKMP_SA_established(connection_t *c, so_serial_t serial);

#define id_is_ipaddr(id) ((id)->get_type(id) == ID_IPV4_ADDR || \
						  (id)->get_type(id) == ID_IPV6_ADDR)
extern bool his_id_was_instantiated(const connection_t *c);

struct state;   /* forward declaration of tag (defined in state.h) */

extern connection_t* con_by_name(const char *nm, bool strict);
extern connection_t* find_host_connection(const ip_address *me,
										  u_int16_t my_port,
										  const ip_address *him,
										  u_int16_t his_port, lset_t policy);
extern connection_t* refine_host_connection(const struct state *st,
											identification_t *id,
											identification_t *peer_ca);
extern connection_t* find_client_connection(connection_t *c,
											const ip_subnet *our_net,
											const ip_subnet *peer_net,
											const u_int8_t our_protocol,
											const u_int16_t out_port,
											const u_int8_t peer_protocol,
											const u_int16_t peer_port);
extern connection_t* find_connection_by_reqid(uint32_t reqid);
extern connection_t* find_connection_for_clients(struct spd_route **srp,
												 const ip_address *our_client,
												 const ip_address *peer_client,
												 int transport_proto);
extern void get_peer_ca_and_groups(connection_t *c,
								   identification_t **peer_ca, 
								   ietf_attributes_t **peer_attributes);

/* instantiating routines
 * Note: connection_discard() is in state.h because all its work
 * is looking through state objects.
 */
struct gw_info; /* forward declaration of tag (defined in dnskey.h) */
struct alg_info;        /* forward declaration of tag (defined in alg_info.h) */
extern connection_t *rw_instantiate(connection_t *c,
									const ip_address *him,
									u_int16_t his_port,
									const ip_subnet *his_net,
									identification_t *his_id);

extern connection_t *oppo_instantiate(connection_t *c,
									  const ip_address *him,
									  identification_t *his_id,
									  struct gw_info *gw,
									  const ip_address *our_client,
									  const ip_address *peer_client);

extern connection_t
  *build_outgoing_opportunistic_connection(struct gw_info *gw,
										   const ip_address *our_client,
										   const ip_address *peer_client);

#define CONN_INST_BUF	BUF_LEN

extern void fmt_conn_instance(const connection_t *c, char buf[CONN_INST_BUF]);

/* operations on "pending", the structure representing Quick Mode
 * negotiations delayed until a Keying Channel has been negotiated.
 */

struct pending; /* forward declaration (opaque outside connections.c) */

extern void add_pending(int whack_sock, struct state *isakmp_sa,
						connection_t *c, lset_t policy, unsigned long try,
						so_serial_t replacing);

extern void release_pending_whacks(struct state *st, err_t story);
extern void unpend(struct state *st);
extern void update_pending(struct state *os, struct state *ns);
extern void flush_pending_by_state(struct state *st);
extern void show_pending_phase2(const struct host_pair *hp, const struct state *st);

extern void connection_discard(connection_t *c);

/* A template connection's eroute can be eclipsed by
 * either a %hold or an eroute for an instance iff
 * the template is a /32 -> /32.  This requires some special casing.
 */
#define eclipsable(sr) (subnetishost(&(sr)->this.client) && subnetishost(&(sr)->that.client))
extern long eclipse_count;
extern connection_t *eclipsed(connection_t *c, struct spd_route **);


/* print connection status */

extern void show_connections_status(bool all, const char *name);
extern int  connection_compare(const connection_t *ca
	, const connection_t *cb);
extern void update_host_pair(const char *why, connection_t *c
	, const ip_address *myaddr, u_int16_t myport
	, const ip_address *hisaddr, u_int16_t hisport);

#endif /* _CONNECTIONS_H */